home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / Technical Docs / Inside Macintosh / New Inside Mac - draft / Files / Files
Encoding:
Text File  |  1992-01-14  |  3.8 MB  |  11,215 lines  |  [ONLN/HLX2]

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. Inside Macintosh:Files    Apple Computer, Inc. © 1991, Apple Computer, Inc.All rights reserved.Printed in the United States of America.The Apple logo is a registered trademark of Apple Computer, Inc. Use of the “keyboard” Apple logo (Option-Shift-K) for commercial purposes without the prior written consent of Apple may constitute trademark infringement and unfair compe-tition in violation of federal and state laws.Apple Computer, Inc. 20525 Mariani Avenue  Cupertino, CA  95014-6299408-996-1010  Apple, the Apple logo, APDA, AppleLink, AppleShare, AppleTalk, Apple IIGS, A/UX, EtherTalk, HyperCard, Hyper-Talk, ImageWriter, LaserWriter, LocalTalk, Mac, Macintosh, MPW, MultiFinder, SANE, and TokenTalk are registered trade-marks of Apple Computer, Inc.Apple Desktop Bus, Balloon Help, Finder, KanjiTalk, Moof, QuickDraw, ResEdit, TrueType, and Zhong-Wen Talk are trade-marks of Apple Computer, Inc.Helvetica and Times are registered trademarks of Linotype Company.ITC Zapf Dingbats is a registered trademark of International Typeface Corporation.MacPaint is a registered trade-mark of Claris Corporation.NuBus is a trademark of Texas Instruments.PostScript is a registered trade-mark, and Illustrator is a trademark, of Adobe Systems Incorporated.Sony is a registered trademark of Sony Corporation.UNIX is a registered trademark of UNIX System Laboratories, Inc.Simultaneously published in the United States and Canada.Limited Warranty on Media and ReplacementEven though Apple has reviewed this manual, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS MANUAL, ITS QUALITY, ACCURACY, MERCHANT-ABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS MANUAL IS SOLD “AS IS,” AND YOU, THE PUR-CHASER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.  IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSE-QUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS MANUAL, even if advised of the possibility of such damages.  THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty.  Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state.Introduction to File ManagementAbout Files1-1File Forks1-2File Size1-4File Access Characteristics1-6The Hierarchical File System1-7Identifying Files and Directories1-9Using Files1-10Testing for File Management Routines1-11Defining a Document Record1-13Creating a New File1-14Opening a File1-15Reading File Data1-19Writing File Data1-21Saving a File1-24Reverting to a Saved File1-27Closing a File1-29Opening Files at Application Startup Time1-31Using a Preferences File1-33Adjusting the File Menu1-35Reference to File Management1-36Data Structures1-36File System Specification Record1-36Standard File Reply Records1-37Application Files Records1-38File Identification Routines1-39File Access Routines1-40Reading, Writing, and Closing Files1-40Manipulating the File Mark1-42Manipulating the End-of-File1-44FSSpec Routines1-45Opening, Creating, and Deleting Files1-46Exchanging the Data in Two Files1-49Creating File System Specifications1-50Volume Access Routines1-51Updating Volumes1-51Obtaining a Volume Reference Number1-52Application Launch File Routines1-53Summary of File Management1-561Introduction to File ManagementThis chapter introduces the data structures and routines your application can use to manage files on Macintosh computers. It explains the basic structure of Macintosh files and the hierarchical file system (HFS) used with Macintosh computers, and it shows how you can use the services provided by the Standard File Package, the File Manager, the Finder, and other system software components to create, open, update, and close files.You should read this chapter if your application implements the commands typically found in an application’s File menu—except for printing commands and the Quit command, which are described elsewhere. This chapter describes how ton    create a new filen    open an existing filen    close a filen    save a document’s data in a filen    save a document’s data in a file under a new namen    revert to the last saved version of a filen    create and read a preferences fileDepending on the requirements of your application, you may be able to accomplish all your file-related activities by following the instructions given in this chapter. If your application has more specialized file management needs, you will need to read some or all of the remaining chapters in the Files section of this volume.This chapter assumes that your application is running in an environment in which the routines that accept file system specification records (FSSpec records) are available. File system specification records, introduced in system software version 7.0, simplify the identification of objects in the file system. Your development environment may provide “glue” that allows you to call those routines in earlier system software versions. If such glue is not available and you want your application to run in system software versions earlier than version 7.0, you need to read the discussion of HFS file-manipulation routines in the chapter “The File Manager” in this volume.This chapter begins with a description of files and how they are organized into folders and volumes. Then it describes how to test for the presence of the FSSpec routines and how to use those routines to perform the file management tasks listed above. The chapter ends with descriptions of the data structures and routines used to perform these tasks. The “Reference” and “Summary” sections in this chapter are subsets of the equivalent sections for the remaining chapters in the Files section of this volume.About FilesTo the user, a file is simply some data stored on a disk. To your application, a file is a named, ordered sequence of bytes stored on a Macintosh volume, divided into two forks (as described in the following section, “File Forks”). The information in a file can be used for any of a variety of purposes. For example, a file might contain the text of a letter or the numerical data in a spreadsheet; these types of files are usually known as documents. Typically a document is a file that a user can create that is associated with a single application, which the user expects to be able to open by double-clicking the document’s icon in the Finder.A file might also contain an application. In that case, the information in the file consists of the executable code of the application itself and any application-specific resources and data. Applications typically allow the user to create and manipulate documents. Some applications also create special files in which they store user-specific settings; such files are known as preferences files.The Macintosh Operating System also uses files for other purposes. For example, the File Manager maintains the hierarchical organization of files and folders on a volume using a special file located on that volume called the volume’s catalog file. Similarly, if virtual memory is in operation, the Operating System stores unused pages of memory in a disk file called the backing-store file.No matter what its function, each file shares certain characteristics with every other file. This section describes these general characteristics of Macintosh files, includingn    file forksn    file size and access characteristicsn    file system organizationn    file naming and identificationFile ForksMany operating systems treat a file simply as a named, ordered sequence of bytes (possibly terminated by a byte having a special value that indicates the end-of-file). As illustrated in Figure 1-1, however, each Macintosh file has two forks, known as the data fork and the resource fork.The two forks of a Macintosh fileA file’s resource fork contains that file’s resources. If the file is an application, the resource fork typically contains menu templates, dialog templates, fonts, icons, and even the executable code of the application itself. A particularly important resource is the application’s 'SIZE' resource, which contains information about the capabilities of the application and its run-time memory requirements. If the file is a document, its resource fork typically contains preference settings, window locations, and document-specific fonts, icons, and so forth.A file’s data fork contains the file’s data. It is simply a series of consecutive bytes of data. In a sense, the data fork of a Macintosh file corresponds to an entire file in operating systems that treat a file simply as a sequence of bytes. The bytes stored in a file’s data fork do not have to exhibit any internal structure, unlike the bytes stored in the resource fork (which consists of a resource map followed by resources). Rather, your application is responsible for interpreting the bytes in the data fork in whatever manner is appropriate. The data fork of a document file might for example contain the text of a letter. Even though a Macintosh file always contains both a resource fork and a data fork, one or both of those forks can be empty. Document files sometimes contain only data (in which case the resource fork is empty). More often, document files contain both resources and data. Application files generally contain resources only (in which case, the data fork is empty). Application files can, however, contain data too.Whether you store specific data in the data fork or in the resource fork of a file depends largely on whether that data can usefully be structured as a resource. For example, if the data you want to store consists of a small number of names and telephone numbers, you can easily define a resource type that pairs each name with its telephone number. Then you can read names and corresponding numbers from the resource file by using Resource Manager routines. To retrieve the data stored in a resource, you simply specify the resource type and ID; you don’t need to know, for instance, how many bytes of data are stored in that resource.In some cases, however, it is not possible or advisable to store your data in resources. The data might be too difficult to put into the kind of structure required by the Resource Manager. For example, it is easiest to store a document’s text, which is usually of variable length, in a file’s data fork. Then you can use File Manager routines to access any byte or group of bytes individually.Even when it is easy to define a resource type for your data, limitations on the Resource Manager might compel you to store your data in the data fork instead. A resource fork can contain at most about 2700 resources. More importantly, the Resource Manager uses a linear search when looking through a file’s resource types and resource IDs. If the number of types or IDs that need to be searched is large, accessing the resource data can become slow. As a rule of thumb, if you need to manage data that would occupy more than about 500 resources total, you should use the data fork instead.In general, you should store data created by the user in a file’s data fork, unless the data is guaranteed to occupy a small number of resources. The Resource Manager was not designed to be a general-purpose data storage and retrieval system. Also, the Resource Manager does not support multiple access to a file’s resource fork. If you want to store data that can be accessed by multiple users of a shared volume, use the data fork.<36pt\>\x12 <8bat\>uBecause the Resource Manager is of limited use in storing large amounts of user-generated data, most of the techniques in “Using Files” show how to use the File Manager to manage information stored in a file’s data fork. See the section “Using a Preferences File” for an example of the use of the Resource Manager to access data stored in a file’s resource fork.File SizeThe size of a file is usually limited only by the size of the volume it’s on. A volume is a portion of a storage device that is formatted to contain files. A volume can be an entire disk or only a part of a disk. A 3.5-inch floppy disk, for instance, is always formatted as one volume. Other memory devices such as hard disks and file servers can contain multiple volumes.Actually, a file on an HFS volume can be as large as 2 GB ($7FFFFFFF bytes). Most volumes are not large enough to hold a file that size. An HFS volume can be as large as 262,144 GB.<36pt\>\x12 <8bat\>uThe size of a volume varies from one type of device to another. Volumes are formatted into chunks known as logical blocks, each of which can contain up to 512 bytes. A double-sided 3.5-inch floppy disk, for instance, usually has 1600 logical blocks, or 800 KB.Generally, however, the size of a logical block on a volume is of interest only to the disk device driver. This is because the File Manager always allocates space to a file in units called allocation blocks. An allocation block is a group of consecutive logical blocks. The File Manager can access a maximum of 65,535 allocation blocks on any volume. For small volumes, such as volumes on floppy disks, the File Manager uses an allocation block size of 1 logical block. To support volumes larger than about 32 MB, the File Manager needs to use an allocation block size that is at least 2 logical blocks. To support volumes larger than about 64 MB, the File Manager needs to use an allocation block that is at least 3 allocation blocks. In this way, by progressively increasing the number of logical blocks in an allocation block, the File Manager can handle larger and larger volumes. Figure 1-2 illustrates how logical blocks are grouped into allocation blocks. Logical blocks and allocation blocksThe size of the allocation blocks on a volume is determined when the volume is initialized and depends on the number of logical blocks it contains. In general, the Disk Initialization Package uses the smallest allocation block size that will allow the File Manager to address the entire volume. A non-empty file fork always occupies at least one allocation block, no matter how many bytes of data that file fork contains. On a 40-MB volume, for example, a file’s data fork occupies at least 1024 bytes (that is, 2 logical blocks), even if it contains only 11 bytes of actual data.To distinguish between the amount of space allocated to a file and the number of bytes of actual data in the file, two numbers are used to describe the size of a file. The physical end-of-file is the number of bytes currently allocated to the file; it’s 1 greater than the number of the last byte in its last allocation block (since the first byte is byte number 0). As a result, the physical end-of-file is always an exact multiple of the allocation block size. The logical end-of-file is the number of those allocated bytes that currently contain data; it’s 1 greater than the number of the last byte in the file that contains data. For example, on a volume having an allocation block size of two logical blocks (that is, 1024 bytes), a file with 508 bytes of data has a logical end-of-file of 509 and a physical end-of-file of 1024 (see Figure 1-3).Logical and physical end-of-fileYou can move the logical end-of-file to adjust the size of the file. When the logical end-of-file is moved to a position more than one allocation block short of the current physical end-of-file, the File Manager automatically deletes the unneeded allocation block from the file. Similarly, you can increase the size of a file by moving the logical end-of-file past the physical end-of-file. When the logical end-of-file is moved past the physical end-of-file, the File Manager automatically adds one or more allocation blocks to the file. The number of allocation blocks added to the file is determined by the volume’s clump size. A clump is a group of contiguous allocation blocks. The purpose of always enlarging files by adding clumps is to reduce file fragmentation on a volume and hence improve the efficiency of reading and writing file data.File Access CharacteristicsA file can be open or closed. Your application can perform certain operations, such as reading and writing data, only on open files. It can perform other operations, such as deleting, only on closed files. When you open a file, the File Manager reads information about the file from its volume and stores that information in a file control block (FCB). The File Manager also creates an access path to the file, a description of the route to be followed when accessing the file. The access path specifies the volume on which the file is located and the location of the file on the volume. Each access path is assigned a unique file reference number (some number greater than 0) that your application uses to refer to it. Multiple access paths can be opened to the same file.For each open access path to a file, the File Manager maintains a current position marker, called the file mark, to keep track of where it is in the file during a read or write operation. The mark is the number of the next byte that will be read or written; each time a byte is read or written, the mark is moved. When, during a write operation, the mark reaches the number of the last byte currently allocated to the file, the File Manager adds another clump to the file.You can read bytes from and write bytes to a file either singly or in sequences of virtually unlimited length. You can specify where each read or write operation should begin by setting the mark; if you don’t, the operation begins at the byte at which the mark currently points.Each time you want to read or write a file’s data, you need to pass the address of a data buffer, a part of RAM (usually in your application’s heap) the File Manager uses to transfer the data to or from your application. You can use a single buffer for each read or write operation, or change the address and size of the buffer as necessary.When your application writes data to a file, the File Manager transfers the data from your application’s data buffer and writes it to the disk cache, a part of RAM (usually in the System heap) that acts as an intermediate buffer when data is read from and written to the file system. When your application requests that data be read from a file, the File Manager looks for the data in the disk cache and transfers it to your application’s data buffer if the data is found in the cache; otherwise, the File Manager reads the requested bytes from the disk and puts them in your data buffer.You can also read a continuous stream of characters or a line of characters from a file. In the first case, you ask the File Manager to read a specific number of bytes: When that many have been read, or when the mark reaches the logical end-of-file, the read operation terminates. In the second case, called newline mode, the read operation terminates when either of the above conditions is met or when a specified character, the newline character, is read. The newline character is usually Return (ASCII code $0D), but it can be any character. Information about newline mode is associated with each access path to a file, and can differ from one access path to another. See the chapter “The File Manager” in this volume for more information about newline mode.<36pt\>\x12 <8bat\>uThe Hierarchical File SystemThe Macintosh Operating System uses a method of organizing files called the hierarchical file system (HFS). In HFS, files are grouped into directories (also called folders), which themselves are grouped into other directories, as illustrated in Figure 1-4. The number listed for each directory is its directory ID. The directory ID is one component of a file system specification, as explained in the next section, “Identifying Files and Directories.”.The Macintosh hierarchical file systemThe Finder is responsible for managing the files and folders on the desktop. It works with the File Manager to maintain the organization of files and folders on a volume. The hierarchical relationship of folders within folders on the desktop corresponds directly to the hierarchical directory structure maintained on the volume. The volume is known as the root directory, and the folders are known as subdirectories, or simply directories.A volume appears on the desktop only after it has been mounted. Ejectable volumes (such as 3.5-inch floppy disks) are mounted when they’re inserted into a disk drive; nonejectable volumes (such as those on hard disks) are mounted automatically at system startup. When a volume is mounted, the File Manager reads information about the volume into memory and places it in a volume control block (VCB). The number of volumes that can be mounted at any time is limited only by the number of drives attached and available memory.When a volume is mounted, the File Manager assigns a volume reference number that you can use to identify the volume for as long as the volume remains mounted. You can also identify a volume by its volume name, a sequence of 1 to 27 printing characters, excluding colons (:). (The File Manager ignores case when comparing names but does recognize diacritical marks.) Whenever possible though, you should use the volume reference number to avoid confusion between volumes with the same name.A volume reference number is valid only until the volume is unmounted. A single volume that is mounted, unmounted, and then remounted can have a different volume reference number when remounted.<36pt\>\x12 <8bat\>uWhen an application ejects a 3.5-inch disk from a drive, the File Manager places the volume off-line. When a volume is off-line, the volume control block is kept in memory and the volume reference number is still valid. If you make a File Manager call that specifies that volume, the File Manager presents the disk switch dialog box to the user. Figure 1-5 shows a sample disk switch dialog box.The disk switch dialog boxWhen the user drags a volume icon into the Trash, that volume is unmounted; the volume control block is released, and the volume is no longer known to the File Manager. In particular, the volume reference number previously assigned to the volume is no longer valid.Each subdirectory is located within a directory called its parent directory. Typically, the parent directory is specified by a parent directory ID, which is simply the directory ID of the parent directory. The File Manager assigns a special parent directory ID to a volume’s root directory. This is primarily to permit a consistent method of identifying files and directories using the volume reference number, the parent directory ID, and the file or directory name. See the next section, “Identifying Files and Directories,” for details.For the most part, your application does not need to be concerned about, or keep track of, the location of files in the file system hierarchy. Most of the files your application opens and saves are specified by the user or another application, and their location is provided to your application by either the Finder or the Standard File Package. One notable exception here concerns preferences files, which are typically stored in the Preferences folder in the currently active System Folder. See “Using a Preferences File” for instructions on finding preferences files.In addition to files, folders, and volumes, a user might also see a fourth type of object on the Finder desktop, namely an alias. An alias is a special kind of file that represents another file, folder, or volume. The Finder and the Standard File Package automatically resolve aliases before passing them to your application, so you generally don’t need to do anything with aliases. For more information on working with alias files, see the chapter “The Finder Interface” in the User Interface Toolbox volume and the chapter “The Alias Manager” in this volume.<36pt\>\x12 <8bat\>uIdentifying Files and DirectoriesThe hierarchical arrangement of files and directories allows you to identify a file or directory uniquely by providing just three pieces of information: its volume reference number, its parent directory ID, and its name within that parent directory. The system software lets you specify these three items together in a file system specification record, defined by the FSSpec data type:TYPE FSSpec                                 =                {file system specification}    RECORD                vRefNum:                Integer;                {volume reference number}                    parID:                LongInt;                {directory ID of parent directory}                    name:                Str63    ;            {filename or directory name}    END;The FSSpec record provides a simple and standard format for specifying files and directories. For example, the Standard File Package procedure StandardGetFile returns information identifying a user-selected file or folder in an FSSpec record. You can pass that identification directly to any file-manipulation routines that accept FSSpec records, such as FSpOpenDF and FSpDelete. In addition, the Alias Manager, Edition Manager, and Finder all use FSSpec records to specify files and directories.Using FilesThis section describes how to perform typical file operations using some of the services provided by the Standard File Package, the File Manager, the Finder, and other system software components. Listing 1-1 shows one way to handle some of the typical File menu commands. Most of the techniques described in this section are illustrated by means of definitions of the functions called in Listing 1-1.Handling the File menu commandsPROCEDURE DoMenuCommand(menuAndItem: LongInt);VAR                myErr: OSErr;BEGIN                CASE HiWord(menuAndItem) OF                    mFile:                        CASE LoWord(menuAndItem) OF                            iNew:                                myErr := DoNewCmd;                            {create a new document}                            iOpen:                                myErr := DoOpenCmd;                            {open an existing document}                            iClose:                                myErr := DoCloseCmd;                            {close the current document}                            iSave:                                myErr := DoSaveCmd;                            {save the current document}                            iSaveAs:                                myErr := DoSaveAsCmd;                {save document under new name}                            iRevert:                                myErr := DoRevertCmd;                    {revert to last saved version}                            OTHERWISE                                ;                        END;                    OTHERWISE                        ;                END;END;Your application should inactivate any menu commands that do not apply to the frontmost window. For example, if the frontmost window is not a document window that belongs to your application, then the Close, Save, Save As, and Revert commands should be dimmed when the menu appears. Similarly, if the frontmost window is a document window that does belong to your application but whose data has not changed since it was last saved, then the Save menu command should be dimmed. See “Adjusting the File Menu” on page 1-33 for details on implementing this feature. The definitions of the application-defined functions used in Listing 1-1 assume that this feature has been implemented.The techniques described in this chapter for manipulating files assume that you identify files and directories by using file system specification records. Because the routines that accept FSSpec records are not available on all versions of system software, you may need to test for the availability of those routines before actually calling any of them. See the next section, “Testing for File Management Routines,” for details.Testing for File Management RoutinesYou can determine whether the FSSpec routines are available by calling the Gestalt function with the gestaltFSAttr selector code, as illustrated in Listing 1-2.Testing for the availability of the FSSpec routinesFUNCTION FSSpecRoutinesAvail: Boolean;VAR                myErr:                    OSErr;                {Gestalt result code}                myFeature:                    LongInt;                {Gestalt response}BEGIN                FSSpecRoutinesAvail := FALSE;                    myErr := Gestalt(gestaltFSAttr, myFeature);                    IF myErr <> noErr THEN                    DoError(myErr)                ELSE                    IF BTst(myFeature, gestaltHasFSSpecCalls) THEN                        FSSpecRoutinesAvail := TRUE;END;To use the procedures defined in the following sections to open and save files, you also need to make sure that the routines StandardGetFile and StandardPutFile are available. You can do this by passing Gestalt the gestaltStandardFileAttr selector and verifying that the bit gestaltStandardFile58 is set in the response value. Also, before using the FindFolder function (as shown, for example, in Listing 1-8), you should call Gestalt with the gestaltFindFolderAttr selector and verify that the gestaltFindFolderPresent bit is set; this indicates that the FindFolder function is available.If the routines that operate on FSSpec records are not available, you can use corresponding File Manager and Standard File Package routines. For example, if you cannot call FSpOpenDF, you can call HOpenDF. That is, instead of writingmyErr := FSpOpenDF(mySpec, fsCurPerm, myFile);you can write something likemyErr := HOpenDF(myVol, myDirID, myName, fsCurPerm, myFile);The only difference is that the FSSpec parameter is replaced by three parameters specifying the volume reference number, the parent directory ID, and the filename. With only a few exceptions, all of the techniques presented in this chapter can be easily adapted to work with high-level HFS routines in place of the FSSpec routines.One notable exception concerns the Standard File Package functions SFGetFile and SFPutFile. The vRefNum field of the reply record passed to both these functions contains a working directory reference number, which is a number that encodes both the directory ID and the volume reference number. In general, you should avoid using this number; instead you can turn it into the corresponding directory ID and volume reference number by calling the GetWDInfo function. See the chapter “The File Manager” in this volume for details on working directory reference numbers.<36pt\>\x12 <8bat\>uDefining a Document RecordWhen a user creates a new document or opens an existing document, your application displays the contents of the document in a window, which provides a standard interface for the user to view and possibly edit the document data. It is useful for your application to define a document record, an application-specific data structure that contains information about the window, any controls in the window (such as scroll bars), and the file (if any) whose contents are displayed in the window. Listing 1-3 illustrates a sample document record for an application that handles text files.A sample document recordTYPE                MyDocRecHnd                    = ^MyDocRecPtr;                MyDocRecPtr                    = ^MyDocRec;                MyDocRec                    =                RECORD                    editRec:                    TEHandle;                        {handle to TextEdit record}                    vScrollBar:                    ControlHandle;                        {vertical scroll bar}                    hScrollBar:                    ControlHandle;                        {horizontal scroll bar}                    fileRefNum:                    Integer;                        {ref num for window’s file}                    fileFSSpec:                    FSSpec;                        {file’s FSSpec}                    windowDirty:                    Boolean                        {has window data changed?}                END;The MyDocRec data type contains fields for information about the TextEdit record that contains the window’s text data and about the horizontal and vertical scroll bars in the window; it also contains a field for the file reference number of the open file (if any) whose data the window displays and a field for the file system specification that identifies that file. The file reference number is needed when the application wants to read or write data from the file, as well as when the file is to be closed. The FSSpec record is needed when the application wants to save any changed data into the file using a “safe-save” procedure.The last field of the MyDocRec data type is a Boolean value that indicates whether the contents of the document in the TextEdit record differ from the contents of the document in the associated file. When your application first reads a file into the window, this field should be set to FALSE. Then, when any subsequent operations alter the contents of the document, you should set the field to TRUE. Your application can inspect this field whenever appropriate to determine if special processing is needed. For example, when the user closes a document window and the windowDirty flag is TRUE, your application should ask the user whether the changed version of the document should be saved in the file. See Listing 1-14 for details.To associate a document record with a particular window, you can simply set a handle to that record as the reference constant of the window (by using the Window Manager procedure SetWRefCon). Then you can retrieve the document record by calling the GetWRefCon function. Listing 1-6 illustrates this process.Creating a New FileThe user expects to be able to create a new document using the New command in the File menu. Listing 1-5 illustrates one way to handle the New menu command.Handling the New menu commandFUNCTION DoNewCmd: OSErr;VAR                myWindow:                WindowPtr;                    {the new document window}                myData:                MyDocRecHnd;                    {the window’s data record}CONST                rDocWindow = 1000;                                    {resource ID of window template}BEGIN                {allocate a new window; see Window Mgr chapter for details}                myWindow := GetNewWindow(rDocWindow, NIL, WindowPtr(-1));                IF myWindow = NIL THEN                    BEGIN                        DoNewCmd := MemError;                        Exit(DoNewCmd);                    END;                {allocate space for the window’s data record}                myData := MyDocRecHnd(NewHandle(SizeOf(MyDocRec)));                IF myData = NIL THEN                    BEGIN                        DoNewCmd := MemError;                        DisposeWindow(myWindow);                        Exit(DoNewCmd);                    END;                        HLock(Handle(myData));                                                    {lock the handle}                WITH myData^^ DO                                                    {fill in window data}                    BEGIN                        editRec := TENew(gDestRect, gViewRect);                        vScroll := GetNewControl(rVScroll, myWind);                        hScroll := GetNewControl(rHScroll, myWind);                        fileRefNum := 0;                                            {no file yet!}                        windowDirty := FALSE;                                        IF (editRec = NIL) OR (vScroll = NIL)                         OR (hScroll = NIL) THEN                            BEGIN                                DoNewCmd := MemError;                                DisposeWindow(myWindow);                                HUnlock(Handle(myData));                                DisposHandle(myData);                                DisposeControl(vScroll);                                DisposeControl(hScroll);                                TEDispose(editRec);                                Exit(DoNewCmd);                            END;                    END;                SetWRefCon(myWindow, LongInt(myData));                                                    {link record to window}                HUnlock(Handle(myData));                                                    {unlock the handle}                DoNewCmd := noErr;END;Note that the DoNewCmd function does not actually create a new file. This is because it is usually better to wait until the user chooses to save a new document before creating a file (mainly because the user might not want to save the document). The DoNewCmd function creates a window, allocates a new document record, and fills out the fields of that record. However, it sets the fileRefNum field of the document record to 0 to indicate that no file is currently associated with this window. Opening a FileYour application might need to open a file in several different situations. For example, if the user launches your application by double-clicking one of its document icons in the Finder, the Finder provides your application with information about the selected file (if your application receives high-level events, the Finder sends it an Open Documents event). At that point, you want to create a new window for the document and read the document data from the file into the window.Your application also opens files in response to the user selecting the Open command in the File menu. In this case, you need to determine which file to open. You can use the Standard File Package to present a standard dialog box that allows the user to navigate the file system hierarchy (if necessary) and select a file of the appropriate type. Once you get the necessary information from the Standard File Package, you can then create a new window for the document and read the document data from the file into the window.As you can see, it makes sense to divide the process of opening a document into several different routines. You can have a routine that elicits a file selection from the user and another routine that creates a window and reads the file data into it. In the sample listings given here, the function DoOpenCmd handles the interaction with the user and DoOpenFile reads a file into a new window.Listing 1-5 shows one way to handle the Open command in the File menu. It uses the Standard File Package routine StandardGetFile to determine which file the user wants to open.Handling the Open menu commandFUNCTION DoOpenCmd: OSErr;VAR                myReply:                StandardFileReply;                            {Standard File reply record}                    myTypes:                SFTypeList;                            {types of files to display}                    myErr:                OSErr;BEGIN                myErr := noErr;                myTypes[0] := 'TEXT';                                            {display text files only}                    StandardGetFile(NIL, 1, myTypes, myReply);                    IF myReply.sfGood THEN                        myErr := DoOpenFile(myReply.sfFile)                ELSE                    myErr := userCanceledErr;                DoOpenCmd := myErr;    END;The StandardGetFile procedure requires a list of file types to display in the dialog box it puts up, illustrated in Figure 1-6. In this case, only text files are to be listed.The default Open dialog boxThe user can scroll through the list of files in the current directory, change the current directory, select a file to open, or cancel the operation altogether. When the user presses either the Cancel or the Open button, StandardGetFile fills out the Standard File reply record you pass to it, which has this structure:TYPE StandardFileReply =    RECORD        sfGood:                    Boolean;                {TRUE if user did not cancel}        sfReplacing:                    Boolean;                {TRUE if replacing file with same name}        sfType:                    OSType;                {file type}        sfFile:                    FSSpec;                {selected item}        sfScript:                    ScriptCode;                {script of selected item’s name}        sfFlags:                    Integer;                {Finder flags}        sfIsFolder:                    Boolean;                {selected item is a folder}        sfIsVolume:                    Boolean;                {selected item is a volume}        sfReserved1:                    LongInt;                {reserved}        sfReserved2:                    Integer;                {reserved}    END;In this situation, the relevant fields of the reply record are the sfGood and sfFile fields. If the user selects a file to open, the sfGood field is set to TRUE and the sfFile field contains an FSSpec record for the selected file. In Listing 1-5, the returned FSSpec record is passed directly to the application-defined function DoOpenFile. Listing 1-6 illustrates a way to define the DoOpenFile function.Opening a fileFUNCTION DoOpenFile (mySpec: FSSpec): OSErr;    VAR                myWindow:                    WindowPtr;                            {window for file data}                    myData:                    MyDocRecHnd;                            {handle to window data}       myFileRefNum:                                    Integer;                            {file reference number}                    myErr:                    OSErr;    BEGIN                myErr := DoNewCmd;                                                {create a new window}                IF myErr <> noErr THEN                    BEGIN                        DoOpenFile := myErr;                        Exit(DoOpenFile);                    END;                myWindow := FrontWindow;                                                {get window pointer}                IF myWindow = NIL THEN                    BEGIN                        DoOpenFile := myErr;                        Exit(DoOpenFile);                    END    ;                SetWTitle(myWindow, mySpec.name);                                                {set window’s title}                    {open the file’s data fork for reading and writing}                myErr := FSpOpenDF(mySpec, fsRdWrPerm, myFileRefNum);                    IF myErr <> noErr THEN                            BEGIN                        DisposeWindow(myWindow);                        DoOpenFile := myErr;                        Exit(DoOpenFile);                    END    ;                {retrieve handle to window’s data record}                    myData := MyDocRecHnd(GetWRefCon(myWindow));                    myData^^.fileRefNum := myFileRefNum;                                                {save file information}                    myData^^.fileFSSpec := mySpec;                                                myErr := DoReadFile(myWindow);                                                {read in file data}                    DoOpenFile := myErr;END;This function is relatively simple because much of the real work is done by the two functions DoNewCmd and DoReadFile. The DoReadFile function is responsible for actually reading the file data from the disk into the TextEdit record associated with the document window. See the next section, “Reading File Data,” for a sample definition of DoReadFile.In Listing 1-6, the key step is the call to FSpOpenDF, which opens the data fork of the specified file. A file reference number—which indicates an access path to the open file—is returned in the third parameter. As you can see, this reference number is saved in the document record, whence it can easily be retrieved for future calls to the FSRead and FSWrite functions.The second parameter in a call to the FSpOpenDF function specifies the access mode for opening the file. For each file, the File Manager maintains access mode information that determines what type of access is available. Most applications support one of two types of access:n    A single user is allowed to read from and write to a file.n    Multiple users are allowed to read from a file, but no one can write to it.Your application can use the following constants to specify these types of access:CONST                    fsCurPerm                = 0;        {request exclusive read/write access; if }                                            { unavailable, request read-only access }                    fsRdPerm                = 1;        {request exclusive read permission}                    fsWrPerm                = 2;        {request exclusive write permission}                    fsRdWrPerm                = 3;        {request exclusive read/write access}To open a file with exclusive read/write access, you can specify fsRdWrPerm. To open a file read-only, specify fsRdPerm. If you want to open a file and don’t know or care which type of access is available, specify fsCurPerm. When you specify fsCurPerm, if no access paths are already open, the file is opened with exclusive read/write access. If other access paths are already open, but they are read-only, another read-only path is opened. If an access path with exclusive read/write permission is already open, the file cannot be opened.Reading File DataOnce you have opened a file, you can read data from it by calling the FSRead function. Generally you need to read data from a file when the user first opens a file or when the user chooses to revert to the last saved version of a document. The DoReadFile function defined in Listing 1-13 illustrates how to use FSRead to read data from a file into a TextEdit record in either situation.Reading data from a fileFUNCTION DoReadFile (myWindow: WindowPtr): OSErr;    VAR    myData:                MyDocRecHnd;                                {handle to a document record}        myFile:                Integer;                                {file reference number}    myLength:                LongInt;                                {number of bytes to read from file}    myText:                TEHandle;                                {handle to TextEdit record}    myBuffer:                Ptr;                                {pointer to data buffer}    myErr:                OSErr;BEGIN    myData := MyDocRecHnd(GetWRefCon(myWindow));                                                            {get window’s data}            myFile := myData^^.fileRefNum;                                                            {get file reference number}    myErr := SetFPos(myFile, fsFromStart, 0);                                                            {set file mark at start}    IF myErr <> noErr THEN        BEGIN            DoReadFile := myErr;            Exit(DoReadFile);        END;    myErr := GetEOF(myFile, myLength);                                                            {get file length}    myBuffer := NewPtr(myLength);                                                            {allocate a buffer}    IF myBuffer = NIL THEN        BEGIN            DoReadFile := MemError;            Exit(DoReadFile);        END;    myErr := FSRead(myFile, myLength, myBuffer);                                                            {read data into buffer}    IF (myErr = noErr) OR (myErr = eofErr) THEN        BEGIN                                                        {move data into TERec}            TESetText(myBuffer, myLength, myData^^.editRec);            myErr := noErr;        END;    DoReadFile := myErr;END;The DoReadFile function takes one parameter specifying the window to read data into. This function first retrieves the handle to that window’s document record and extracts the file’s reference number from that record. Then DoReadFile calls the SetFPos function to set the file mark to the beginning of the file having that reference number. There is no need to check that myFile is nonzero, because SetFPos returns an error if the reference number you pass in is not a valid file reference number.The second parameter to SetFPos specifies the file positioning mode; in general, it can contain one of the following values:CONST                    fsAtMark                = 0;        {at current mark}                    fsFromStart                = 1;        {set mark relative to beginning of file}                    fsFromLEOF                = 2;        {set mark relative to logical end-of-file}                    fsFromMark                = 3;        {set mark relative to current mark}If you specify fsAtMark, the mark is left wherever it’s currently positioned and the third parameter of SetFPos is ignored. The other three constants let you position the mark relative to either the beginning of the file, the logical end-of-file, or the current mark. If you specify one of these three constants, the third parameter contains the byte offset (either positive or negative) from the specified point. Here, the appropriate positioning mode is relative to the beginning of the file.If DoReadFile successfully positions the file mark, it next determines the number of bytes in the file by calling the GetEOF function. The key step in the DoReadFile function is the call to FSRead, which reads the specified number of bytes from the file into the specified buffer. In this case, the data is read into a temporary buffer; then the data is moved into the TextEdit record associated with the file. FSRead returns the number of bytes actually read from the file in the myLength parameter.Writing File DataGenerally your application writes data to a file in response to the File menu commands Save or Save As. However, your application might also incorporate a scheme that automatically saves all open documents to disk every few minutes. It therefore makes sense to isolate the routines that handle the menu commands from the routines that handle the actual writing of data to disk. This section shows how to write the data stored in a TextEdit record to a file. See “Saving a File” for instructions on handling the Save and Save As menu commands.It is very easy to write data from a specified buffer into a specified file. You simply position the file mark at the beginning of the file (using SetFPos), write the data into the file (using FSWrite), and resize the file to the number of bytes actually written (using SetEOF). Listing 1-8 illustrates this sequence.Writing data into a fileFUNCTION DoWriteData (myWindow: WindowPtr; myTemp: Integer): OSErr;    VAR    myData:                MyDocRecHnd;                                {handle to a document record}        myLength:                LongInt;                                {number of bytes to write to file}    myText:                TEHandle;                                {handle to TextEdit record}    myBuffer:                Handle;                                {handle to actual text in TERec}    myVol:                Integer;                                {volume reference number of myFile}        myErr:                OSErr;BEGIN    myData := MyDocRecHnd(GetWRefCon(myWindow));                                                            {get window’s data record}            myText := myData^^.editRec;                                                            {get TERec}    myBuffer := myText^^.hText;                                                            {get text buffer}    myLength := myText^^.teLength;                                                            {get text buffer size}    myErr := SetFPos(myTemp, fsFromStart, 0);                                                            {set file mark at start}    IF myErr = noErr THEN                                                            {write buffer into file}        myErr := FSWrite(myTemp, myLength, myBuffer^);        IF myErr = noErr THEN                                                            {adjust file size}        myErr := SetEOF(myTemp, myLength);        IF myErr = noErr THEN                                                            {find volume file is on}        myErr := GetVRefNum(myTemp, myVol);        IF myErr = noErr THEN                                                            {flush volume}         myErr := FlushVol(NIL, myVol);        IF myErr = noErr THEN                                                            {show file is up to date}                                                    myData^^.windowDirty := FALSE;        DoWriteData := myErr;END;The DoWriteData function first retrieves the TextEdit record attached to the specified window and extracts the address and length of the actual text buffer from that record. Then it calls SetFPos, FSWrite, and SetEOF as just explained. Finally, DoWriteData determines the volume containing the file (using the GetVRefNum function) and flushes that volume (using FlushVol). This is necessary to ensure that both the file’s data and the file’s catalog entry are updated.Notice that the DoWriteData function takes a second parameter, myTemp, which should be a file reference number of a temporary file, not the file reference number of the file associated with the window whose data you want to write. If you were to pass the reference number of the file associated with the window, you would risk corrupting the file. For when you position the file mark at the beginning of the file and call FSWrite, the existing file data is overwritten. If FSWrite does not complete successfully, it is very likely that the file on disk does not contain the correct document data.To avoid corrupting the file containing the saved version of a document, always call DoWriteData specifying the file reference number of some new, temporary file. Then, when DoWriteData completes successfully, you can swap the contents of the temporary file and the existing file using the FSpExchangeFiles function. Listing 1-8 illustrates how to update a file on disk safely; it shows a sequence of updating, renaming, saving, and deleting files that preserves the contents of the existing file until the new version is safely recorded. Updating a file safelyFUNCTION DoWriteFile (myWindow): OSErr;    VAR    myData:                MyDocRecHnd;                    {handle to window’s document record}        myFSpec:                FSSpec;                    {FSSpec for file to update}    myTSpec:                FSSpec;                    {FSSpec for temporary file}    myTime:                LongInt;                    {current time; for temporary filename}    myName:                Str255;                    {name of temporary file}    myTemp:                Integer;                    {file reference number of temporary file}    myVRef:                Integer;                    {volume reference number of temporary file}    myDirID:                LongInt;                    {directory ID of temporary file}    myErr:                OSErr;BEGIN    myData := MyDocRecHnd(GetWRefCon(myWindow));{get that window’s data}            myFSpec := myData^^.fileFSSpec;                                                        {get FSSpec for existing file}    GetDateTime(myTime);                                                        {create a temporary filename}    NumToString(myTime, myName);        {find the temporary folder on file’s volume; create it if necessary}    myErr := FindFolder(myFSpec.vRefNum, kTemporaryFolderType,                                kCreateFolder, myVRef, myDirID);    IF myErr = noErr THEN                                                        {make an FSSpec for temp file}        myErr := FSMakeFSSpec(myVRef, myDirID, myName, myTSpec);                                IF myErr = noErr THEN                                                        {create a temporary file}        myErr := FSpCreate(myTSpec, 'trsh', 'trsh', smSystemScript);        IF myErr = noErr THEN                                                        {open the newly created file}        myErr := FSpOpenDF(myTSpec, fsRdWrPerm, myTemp);                                            IF myErr = noErr THEN                                                        {write data to the temp file}        myErr := DoWriteData(myWindow, myTemp);        IF myErr = noErr THEN                                                        {close the temporary file}        myErr := FSClose(myTemp);        IF myErr = noErr THEN                                                        {swap data in the two files}        myErr := FSpExchangeFiles(myTSpec, myFSpec);                                    IF myErr = noErr THEN                                                        {delete the temporary file}        myErr := FSpDelete(myTSpec);    IF myErr = noErr THEN        myData^^.windowDirty := FALSE;                                                    {mark window’s not dirty}    DoWriteFile := myErr;END;The essential idea behind this “safe save” process is to save the data in memory into a new file and then to exchange the contents of the new file and the old version of the file by calling FSpExchangeFiles. FSpExchangeFiles does not move the data on the volume; it merely changes the information in the volume’s catalog and, if the files are open, in their file control blocks (FCBs). The catalog entry for a file containsn    fields that describe the physical data, such as the first allocation block, physical end, and logical end of both the resource and data forksn    fields that describe the file within the file system, such as file ID and parent directory IDFields that describe the data remain with the data; fields that describe the file remain with the file. The creation date remains with the file; the modification date remains with the data. (For a more complete description of the FSpExchangeFiles function, see the chapter “The File Manager” in this volume.)Saving a FileThere are several ways in which a user can indicate that the current contents of a document should be saved (that is, written to disk). The user can select the File menu commands Save or Save As, or the user can click the Save button in a dialog box that you display when the user attempts to close a document that is dirty (that is, a document whose contents have changed since the last time it was saved). You can handle the Save menu command quite easily, as illustrated in Listing 1-10.Handling the Save menu commandFUNCTION DoSaveCmd: OSErr;VAR    myWindow:                WindowPtr;                            {pointer to the front window}        myData:                MyDocRecHnd;                            {handle to a document record}        myErr:                OSErr;BEGIN    myWindow := FrontWindow;                                            {get front window and its data}    myData := MyDocRecHnd(GetWRefCon(myWind));        IF myData^^.fileRefNum <> 0 THEN                                            {if window has a file already}        myErr := DoWriteFile(myWind);                                        {then write contents to disk}    ELSE        myErr := DoSaveAsCmd;                                        {else ask for a filename}    DoSaveCmd := myErr;END;DoSaveCmd simply checks to see whether the frontmost window already has a file associated with it. If it does, then DoSaveCmd calls DoWriteFile to write the data to disk (using the “safe save” process illustrated in the previous section). Otherwise, if no file exists for that window, DoSaveCmd calls DoSaveAsCmd. Listing 1-11 shows a way to define the DoSaveAsCmd function.Handling the Save As menu commandFUNCTION DoSaveAsCmd: OSErr;    VAR    myWindow:            WindowPtr;                                {pointer to the front window}        myData:            MyDocRecHnd;                                {handle to a document record}    myReply:            StandardFileReply;    myFile:            Integer;                                {file reference number}            myErr:            OSErr;BEGIN    myWindow := FrontWindow;                                            {get front window and its data}    myData := MyDocRecHnd(GetWRefCon(myWindow));        StandardPutFile('Save this document as:', 'Untitled', myReply);        IF myReply.sfGood THEN                                            {user saves file}        BEGIN            IF NOT myReply.sfReplacing THEN                myErr := FSpCreate(myReply.sfFile, 'MYAP', 'TEXT');            IF myErr <> noErr THEN                Exit(DoSaveAsCmd);                myData^^.fileFSSpec := myReply.sfFile;                                    IF myData^^.fileRefNum <> 0                                    {if window already has a file}                myErr := FSClose(myData^^.fileRefNum);                                                {close it}            IF myErr = noErr THEN                    myErr := FSpOpenDF(myData^^.fileFSSpec, fsRdWrPerm, myFile);                IF myErr = noErr THEN                    BEGIN                    myData^^.fileRefNum := myFile;                        SetWTitle(myWindow, myReply.sfName);                        myErr := DoWriteFile(myWindow);                    END;            DoSaveAsCmd := myErr;        END;END;The StandardPutFile function is similar to the StandardGetFile function discussed earlier in this chapter. It manages the user interface for the default Save dialog box, illustrated in Figure 1-7.The default Save dialog boxIf the user clicks the New Folder button, the Standard File Package presents a subsidiary dialog box like the one shown in Figure 1-8.The New Folder dialog boxIf the user asks to save a file with a name that already exists at the specified location, the Standard File Package displays a subsidiary dialog box to verify that the new file should replace the existing file, like the one shown in Figure 1-9.The name conflict dialog boxNote in Listing 1-11 that if the user is not replacing an existing file, the DoSaveAsCmd creates a new file and records the new FSSpec record in the window’s document record. Otherwise, if the user is replacing an existing file, DoSaveAsCmd simply records the FSSpec record returned by StandardGetFile in the window’s document record.Reverting to a Saved FileMany applications that manipulate files provide a menu command that allows the user to revert to the last version of a document. The technique for handling this command is relatively simple. First you should put up a dialog box asking whether to revert to the last saved version of the file, as illustrated in Figure 1-10.A Revert to Saved dialog boxIf the user selects the No button, nothing should happen to the current document. If, however, the user confirms the menu command by selecting the OK button, you just need to call DoReadFile to read the disk version of the file back into the window. Listing 1-13 illustrates how to implement a Revert to Saved menu command.Handling the Revert to Saved menu commandFUNCTION DoRevertCmd: OSErr;    VAR    myWindow:                WindowPtr;                            {window for file data}        myData:                MyDocRecHnd;                            {handle to window data}        myFile:                Integer;                            {file reference number}    myName:                Str255;                            {file’s name}        myDialog:                DialogPtr;                            {pointer to modal dialog box}    myItem:                Integer;                            {item hit in modal dialog}    myPort:                GrafPtr;                            {the original graphics port}    CONST    kRevertDialog = 128;                                            {resource ID of Revert to Saved dialog}BEGIN    myWindow := FrontWindow;                                            {get pointer to front window}                                                {get handle to window’s data record}        myData := MyDocRecHnd(GetWRefCon(myWindow));    GetWTitle(myWindow, myName);                                            {get file’s name}    ParamText(myName, '', '', '');    myDialog := GetNewDialog(kRevertDialog, nil, WindowPtr(-1));    GetPort(myPort);        SetPort(myDialog);    REPEAT        ModalDialog(NIL, myItem);    UNTIL (myItem = iOK) OR (myItem = iCancel);    DisposeDialog(myDialog);        SetPort(myPort);                                            {restore previous grafPort}    IF myItem = iOK THEN        DoRevertCmd := DoReadFile(myWindow);        ELSE        DoRevertCmd := noErr;    END;The DoRevertCmd function retrieves the document record handle from the frontmost window’s reference constant field and then gets the window’s title (which is also the name of the file) and inserts it into a modal dialog. If the user hits the OK button, DoRevertCmd calls the DoReadFile function to read the data from the file into the window. Otherwise, DoRevertCmd simply exits without changing the data in the window.Closing a FileIn most cases, your application closes a file in response to a user clicking in a window’s close box or selecting the Close command in the File menu. The Close menu command should be active only when there is actually an active window open on the desktop. If there is an active window, you need to determine whether it belongs to your application; if so, you need to handle dialog windows and document windows differently, as illustrated in Listing 1-13.Handling the Close menu commandFUNCTION DoCloseCmd: OSErr;    VAR                myWindow:                WindowPtr;                myData:                MyDocRecHnd;                            {handle to a document record}                myErr:                OSErr;BEGIN                myWindow := FrontWindow;                                            {get window to be closed}                IF IsDAWindow(myWindow) THEN                    CloseDeskAcc(WindowPeek(myWindow)^.windowKind)                ELSE IF IsDialogWindow(myWindow) THEN                    HideWindow(myWindow)                                        {for dialogs, hide the window}                ELSE IF IsAppWindow(myWindow) THEN                    BEGIN                        myData := MyDocRecHnd(GetWRefCon(myWindow));                            myErr := DoCloseFile(myData);                        IF myErr = noErr THEN                            myErr := DoCloseWindow(myWindow);                    END;                DoCloseCmd := noErr;END;If the window to be closed is a dialog window, this procedure just hides the window. If the window to be closed is a document window, DoCloseCmd retrieves its document record handle and calls both DoCloseFile and DoCloseWindow. Before you close the file associated with a window, you should first check to see if the contents of the window have changed since the last time the document was saved. If the contents have changed, you should ask the user whether to save those changes. Listing 1-14 illustrates one way to do this.Closing a fileFUNCTION DoCloseFile (myData: MyDocRecHnd): OSErr;    VAR    myErr:                OSErr;    myDialog:                DialogPtr;                        {pointer to modal dialog box}    myItem:                Integer;                        {item hit in modal dialog}    myPort:                GrafPtr;                        {the original graphics port}    CONST    kSaveChangesDialog = 129;                                        {resource of Save changes dialog}BEGIN    IF myData^^.windowDirty THEN                                        {see whether window is dirty}        BEGIN            myItem := CautionAlert(kSaveChangesDialog, NIL);                IF myItem = iOK THEN                myErr := DoSaveCmd;        END;    IF myData^^.fileRefNum <> 0 THEN        BEGIN            myErr := FSClose(myData^^.fileRefNum);            IF myErr = noErr THEN                BEGIN                    myErr := FlushVol(NIL, myData^^.fileFSSpec.vRefNum);                    myData^^.fileRefNum := 0;                            {clear the file ref. num.}                END;        END;    DoCloseFile := myErr;END;If the document is an existing file that has not been changed since it was last saved, your application can simply call the FSClose function. This routine takes any unwritten data remaining in the volume buffer and writes it out to disk. It also updates the information maintained on the volume for that file and removes the access path. The information about the file is not actually written to the disk, however, until the volume is flushed, ejected, or unmounted. To keep the file information current, it’s a good idea to follow each call to FSClose with a call to the FlushVol function.If the contents of an existing file have been changed, or if a new file is being closed for the first time, your application can call the Dialog Manager routine CautionAlert to ask the user whether or not to save the changes. If the user chooses not to save the file, you can just call FSClose and dispose of the window. Otherwise, DoCloseFile calls the DoSaveCmd function to save the file to disk.Opening Files at Application Startup TimeA user often launches your application by double-clicking one of its document icons or by selecting one or more document icons and choosing the Open command in the Finder’s File menu. In these cases, your application needs to determine which files the user selected so it can open each one and display its contents in a window. There are two ways in which your application can determine this.If the user opens a file and if your application supports high-level events, the Finder sends it an Open Documents event or Print Documents event. Your application then needs to determine which file or files to open and react accordingly. For a complete description of how to process the Open Documents event, see the chapter “The Apple Event Manager” in the Toolbox volume.If at all possible, your application should support high-level events.<36pt\>\x12 <8bat\>uIf your application does not support high-level events, you need to ask the Finder at application launch time whether or not the user launched the application by selecting some documents. You can do this by calling the CountAppFiles procedure and seeing whether the count of files is 1 or more. Then you can call the procedures GetAppFiles and ClrAppFiles to retrieve the information about the selected files. The technique is illustrated in Listing 1-15.Opening files at application launch timePROCEDURE DoInitFiles;VAR    myNum:            Integer;                {number of files to be opened or printed}    myJob:            Integer;                {open or print the files?}    index:            Integer;                {index of current file}    myFile:            AppFile;                {file info}    mySpec:            FSSpec;                {file system specification}    myErr:            OSErr;        BEGIN    CountAppFiles(myJob, myNum);        IF myNum > 0 THEN                                                        {user selected some files}                IF myJob = appOpen THEN                                                    {files are to be opened}                FOR index := 1 TO myNum DO                    BEGIN                    GetAppFiles(index, myFile);                                        {get file info from Finder}                    myErr := FSMakeFSSpec(myFile.vRefNum, 0, myFile.fName,                                                     mySpec);            {make an FSSpec to hold info}                                                            myErr := DoOpenFile(mySpec);                                        {read in file's data}                        ClrAppFiles(index)    ;                                    {show we’ve got the info}                    END;END;The CountAppFiles procedure determines how many files, if any, the user selected at application startup time. If the myNum parameter is nonzero, then myJob contains a value that indicates whether the files were selected for opening or printing. Currently, myJob can have one of two values:CONST                appOpen            =    0;        {open the document(s)}                appPrint            =    1;        {print the document(s)}In Listing 1-15, if the files are to be opened, then DoInitFiles calls the GetAppFiles procedure for each file to obtain information about that file. GetAppFiles returns the information in a record of type AppFile.TYPE AppFile                                 =RECORD                vRefNum:                Integer;            {working directory ID}                fType:                OSType;            {file type}                versNum:                Integer;            {version number; ignored}                fName:                Str255;            {file name}END;Because the function DoOpenFile takes an FSSpec record as a parameter, DoInitFiles next converts the information returned in the myFile parameter into an FSSpec, using FSMakeFSSpec. Then DoInitFiles calls DoOpenFile to read the file data and ClrAppFiles to let the Finder know that it has processed the information for that file.The vRefNum field of an AppFiles record does not contain a volume reference number; instead it contains a working directory reference number, which encodes both the volume reference number and the parent directory ID. (That’s why the second parameter passed to FSMakeFSSpec in Listing 1-15 is 0.)<36pt\>\x12 <8bat\>uUsing a Preferences FileMany applications allow the user to alter various settings that control the operation or configuration of the application. For example, your application might allow the user to specify the size and placement of any new windows or the default font used to display text in those windows. To record user preferences that your application can retrieve whenever it is launched, you can create a preferences file.In deciding how to structure your preferences file, it is important to distinguish document-specific settings from application-specific settings. Some user-specifiable settings affect only a particular document. For example, the user might have changed the text font in a particular window. When you save the text in the window, you also want to save the current font setting. Generally you can do this by storing the font name in a resource in the document file’s resource fork. Then, when the user opens that document again, you check for the presence of such a resource, retrieve the information stored in it, and set the document font accordingly.Some settings, such as a default text font, are not specific to a particular document. You might store such settings in the application’s resource fork, but generally it is better to store them in a separate preferences file. The main reason for this is to avoid problems that can arise if an application is located on a server volume. If preferences are stored in resources in the application’s resource fork, those preferences apply to all users executing that application. Worse yet, the resources can become corrupted if several different users attempt to alter the settings at the same time.To avoid such problems, it is best to store application-specific settings in a preferences file. The Operating System provides a special folder in the System Folder, called Preferences, where you can store that file. Listing 1-16 illustrates a way to open your application’s preferences file.Opening a preferences filePROCEDURE DoGetPreferences;    VAR                myErr:            OSErr;                myVRef:            Integer;                {volume ref num of Preferences folder}                myDirID:            LongInt;                {dir ID of Preferences folder}                mySpec:            FSSpec;                {FSSpec for the preferences file}                myName:            Str255;                {name of the application}                myRef:            Integer;                {ref num of app’s resource file; ignored}                myHand:            Handle;                {handle to Finder information; ignored}                myRefNum:            Integer;                {file reference number}CONST                kPrefID = 128;                            {resource ID of STR# with filename}BEGIN                {determine the name of the preferences file}                GetIndString(myStr, kPrefID, 1);}                                {find the Preferences folder in the System Folder}                myErr := FindFolder(kOnSystemDisk, kPreferencesFolderType,                                             kDontCreateFolder, myVRef, myDirID);                    IF myErr = noErr THEN                        myErr := FSMakeFSSpec(myVRef, myDirID, myName, mySpec);                                            IF myErr = noErr THEN                        myRefNum := FSpOpenResFile(mySpec, fsCurPerm);                    {read your preference settings here}                CloseResFile(myRefNum);END;DoGetPreferences first determines the name of the preferences file it is to open and read.  To allow easier localization, you should store the name in a resource of type 'STR#' in your application’s resource file. The DoGetPreferences routine assumes that the name is stored as the first string in the resource having ID kPrefID. The technique shown here assumes that your preference settings can all be stored in resources. As a result, Listing 1-16 calls the function FSpOpenResFile to open the resource fork of your preferences file. See the chapter “The Resource Manager” in the Toolbox volume for complete details on opening resource files and reading resources from them.Adjusting the File MenuYour application should dim any File menu commands that are not available at the time the user pulls down the File menu. For example, if your application does not yet have a document window open, then the Save, Save As, and Revert commands should be dimmed out. You can adjust the File menu easily using the technique shown in Listing 1-17.Adjusting the File menuPROCEDURE DoAdjustMenus;VAR                myWindow:                WindowPtr;                myMenu:                MenuHandle;                myData:                MyDocRecHnd;                                    {handle to window data}    BEGIN                myWindow := FrontWindow;                IF myWindow = NIL THEN                    BEGIN                        myMenu := GetMHandle(mFile);                        DisableMenu(myMenu, iSave);                                            {disable Save}                        DisableMenu(myMenu, iSaveAs);                                            {disable Save As}                        DisableMenu(myMenu, iRevert);                                            {disable Revert}                        DisableMenu(myMenu, iClose);                                            {disable Close}                    END                ELSE IF IsAppWindow(myWindow) THEN                    BEGIN                        myData := MyDocRecHnd(GetWRefCon(myWindow));                            myMenu := GetMHandle(mFile);                        EnableMenu(myMenu, iSaveAs);                                            {enable Save As}                        EnableMenu(myMenu, iClose);                                            {enable Close}                        IF myData^^.windowDirty THEN                            BEGIN                                EnableMenu(myMenu, iSave);                                            {enable Save}                                EnableMenu(myMenu, iRevert);                                            {enable Revert}                            END                        ELSE                            BEGIN                                DisableMenu(myMenu, iSave);                                            {disable Save}                                DisableMenu(myMenu, iRevert);                                            {disable Revert}                            END;                    END;END;Your application should call DoAdjustMenus whenever it receives a mouse-down event in the menu bar. (No doubt you also want to include code appropriate for enabling and disabling other menu items too.) See the chapter “The Menu Manager” in the Macintosh Toolbox volume for details on the menu enabling and disabling procedures used in Listing 1-17.Reference to File ManagementThis section describes the data structures and routines used in this chapter to illustrate basic file management operations. The “Data Structures” section shows the Pascal data structures for the file system specification record and the standard file reply record. The sections that follow describe the Standard File Package routines for opening and saving documents and the File Manager routines for accessing files, manipulating files and directories, accessing volumes, and gettting information about documents to be opened when your application is launched.For a description of other file-related data structures and routines, see the chapters “The File Manager” and “The Standard File Package” in this volume.Data StructuresThis section describes the data structures that your application can use to exchange information with the File Manager and the Standard File Package. The techniques described in this chapter use file system specification records and standard file reply records.File System Specification RecordThe file system specification record for files and directories is defined by the FSSpec data type.TYPE FSSpec                             =                    {file system specification}RECORD                vRefNum:                Integer;                {volume reference number}                parID:                LongInt;                {directory ID of parent directory}                name:                Str63;                {filename or directory name}END;vRefNum    The volume reference number of the volume containing the specified file or directory.parID    The directory ID of the directory containing the specified file or directory.name    The name of the specified file or directory.Standard File Reply RecordsThe procedures StandardGetFile and StandardPutFile both return information to your application using a standard file reply record, which is defined by the StandardFileReply data type. The reply record identifies selected files with a file system specification record, which you can pass directly to many of the File Manager functions described in the sections that follow. The reply record also contains fields that support several Finder features.TYPE StandardFileReply =    RECORD        sfGood:                    Boolean;                {TRUE if user did not cancel}        sfReplacing:                    Boolean;                {TRUE if replacing file with same name}        sfType:                    OSType;                {file type}        sfFile:                    FSSpec;                {selected item}        sfScript:                    ScriptCode;                {script of selected item’s name}        sfFlags:                    Integer;                {Finder flags}        sfIsFolder:                    Boolean;                {selected item is a folder}        sfIsVolume:                    Boolean;                {selected item is a volume}        sfReserved1:                    LongInt;                {reserved}        sfReserved2:                    Integer;                {reserved}    END;sfGood    Reports whether the reply record is valid. The value is TRUE after the user clicks Save or Open, FALSE after the user clicks Cancel. When the user has completed the dialog box, the other fields in the reply record are valid only if sfGood is TRUE.sfReplacing    Reports whether a file to be saved replaces an existing file of the same name. This field is valid only after a call to the StandardPutFile or CustomPutFile procedure. When the user assigns a name that duplicates that of an existing file, the Standard File Package asks for verification by displaying a subsidiary dialog box (illustrated in Figure 1-9). If the user verifies the name, the Standard File Package sets the sfReplacing field to TRUE and returns to your application; if the user cancels the overwriting of the file, the Standard File Package returns to the main dialog box. If the name does not conflict with an existing name, the Standard File Package sets the field to FALSE and returns. Your application can rely on the value of this field instead of checking for and handling name conflicts itself.sfType    Contains the file type of the selected file. (File types are described in the chapter “The Finder Interface” of the Toolbox volume.) Only StandardGetFile and CustomGetFile return a file type in this field.sfFile    Describes the selected file, folder, or volume with a file system specification record. If the selected item is an alias for another item, the Standard File Package resolves the alias and places the file system specification record for the target in the sfFile field when the user completes the dialog. If the selected file is a stationery pad, the reply record describes the file itself, not a copy of the file.sfScript    Identifies the script in which the name of the document is to be displayed. This information is used by the Finder and by the Standard File Package. A script code of smSystemScript (–1) represents the default system script.sfFlags    Contains the Finder flags from the Finder information record in the catalog entry for the selected file. (See the chapter “The Finder Interface” in the Toolbox volume for a description of the Finder flags.) This field is returned only by StandardGetFile and CustomGetFile. If your application supports stationery, it should check the stationery bit in the Finder flags to determine whether to treat the selected file as stationery. Unlike the Finder, the Standard File Package does not automatically create a document from a stationery pad and pass your application the new document. If the user opens a stationery document from within an application that does not support stationery, the Standard File Package displays a dialog box warning the user that the master copy is being opened.sfIsFolder    Reports whether the selected item is a folder (TRUE) or a file or volume (FALSE).sfIsVolume    Reports whether the selected item is a volume (TRUE) or a file or folder (FALSE).sfReserved1    Reserved.sfReserved2    Reserved.Application Files RecordsThe GetAppFiles procedure returns information about files opened at application launch time in an applicaiton file record, defined by the AppFile data type:TYPE AppFile                                 =RECORD                vRefNum:                Integer;            {working directory reference number}                fType:                OSType;            {file type}                versNum:                Integer;            {version number; ignored}                fName:                Str255;            {file name}END;vRefNum    A working directory reference number that encodes the volume and parent directory of the file.fType    The file type.versNum    Reserved.fName    The file’s name.File Identification RoutinesIf your application has no special interface requirements, you can use the StandardGetFile and StandardPutFile procedures to display the default dialog boxes for opening and saving documents. For a description of more advanced file identification routines, see the chapter “The Standard File Package” in this volume.1StandardGetFileYou can use the StandardGetFile procedure to display the default Open dialog box when the user is opening a file.PROCEDURE StandardGetFile (fileFilter: FileFilterProcPtr;                                    numTypes: Integer;                                     typeList: SFTypeList;                                     VAR reply: StandardFileReply);fileFilter    A pointer to an optional file filter function, provided by your application, through which StandardGetFile passes files of the specified types.numTypes    The number of file types to be displayed. If you specify a numTypes value of –1, the first filtering passes files of all types. typeList    A list of file types to be displayedreply    The reply record, which StandardGetFile fills in before returning.DESCRIPTIONStandardGetFile presents a dialog box through which the user specifies the name and location of a file to be opened. While the dialog box is active, StandardGetFile gets and handles events until the user completes the interaction, either by selecting a file to open or by canceling the operation. StandardGetFile returns the user’s input in a standard file reply record.The fileFilter, numTypes, and typeList parameters together determine which files appear in the display list. The first filtering is by file type, which you specify in the numTypes and typeList parameters. The numTypes parameter specifies the number of file types to be displayed. You can specify one or more types. If you specify a numTypes value of –1, the first filtering passes files of all types.The fileFilter parameter points to an optional file filter function, provided by your application, through which StandardGetFile passes files of the specified types. See the chapter “The Standard File Package” in this volume for a complete description of how you specify this filter function.1StandardPutFileYou can use the StandardPutFile procedure to display the default Save dialog box when the user is saving a file.PROCEDURE StandardPutFile (prompt: Str255; defaultName: Str255;                                    VAR reply: StandardFileReply);prompt    Specifies the prompt message to be displayed over the text field.defaultName    Contains the initial name of the file..reply    The reply record, which StandardPutFile fills in before returning.DESCRIPTIONStandardPutFile presents a dialog box through which the user specifies the name and location of a file to be written to. While the dialog box is active, StandardPutFile gets and handles events until the user completes the interaction, either by selecting a name and authorizing the save or by canceling the save. StandardPutFile returns the user’s input in a standard file reply record.File Access RoutinesThis section describes the File Manager’s file access routines. When you call one of these routines, you specify a file by a path reference number (which the File Manager returns to your application when your application opens the file). Unless your application has very specialized needs, you should be able to manage all file access (for example, writing data to the file) using the routines described in this section. Typically you use these routines to operate on a file’s data fork, but in certain circumstances you might want to use them on a file’s resource fork as well.Reading, Writing, and Closing FilesYou can use the functions FSRead, FSWrite, and FSClose to read data from a file, write data to a file, and close an open file. All three of these functions operate on open files. You can use any one of a variety of routines to open a file (for example, FSpOpenDF).1FSReadYou can use the FSRead function to read any number of bytes from an open file.FUNCTION FSRead (refNum: Integer; VAR count: LongInt;                         buffPtr: Ptr): OSErr;refNum    The file reference number of an open file.count    On input, the number of bytes to read; on output, the number of bytes actually read.buffPtr    A pointer to the data buffer into which the bytes are to be read.DESCRIPTIONFSRead attempts to read the requested number of bytes from the specified file into the specified buffer. The read operation begins at the current mark, so you might want to set the mark first with the SetFPos function. If you try to read past the logical end-of-file, FSRead moves the mark to the end-of-file and returns eofErr as its function result.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openeofErr    –39    End-of-filerfNumErr    –51    Bad reference number1FSWriteYou can use the FSWrite function to write any number of bytes to an open file.FUNCTION FSWrite (refNum: Integer; VAR count: LongInt;                         buffPtr: Ptr): OSErr;refNum    The file reference number of an open file.count    On input, the number of bytes to write to the file; on output, the number of bytes actually written.buffPtr    A pointer to the data buffer from which the bytes are to be written.DESCRIPTIONFSWrite takes the specified number of bytes from the specified data buffer and attempts to write them to the specified file. The write operation begins at the current mark, so you might want to set the mark first with the SetFPos function.RESULT CODESnoErr    0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openwPrErr     –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr     –46    Software volume lockrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writing1FSCloseYou can use the FSClose function to close an open file.FUNCTION FSClose (refNum: Integer): OSErr;refNum    The file reference number of an open file.DESCRIPTIONFSClose removes the access path for the specified file, writes the contents of the volume buffer to the volume, and updates the file’s entry in the file directory.There’s no guarantee that any bytes have been written until FlushVol is called.<36pt\>\x12 <8bat\>uMake sure you do not call FSClose with a file reference number of a file that has already been closed. Attempting to close the same file twice may result in loss of data on a volume. See “File Control Blocks” in the chapter “The File Manager” in this volume for a description of how this can happen.<36pt\>\x12 <8bat\>sRESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorfnOpnErr    –38    File not openfnfErr    –43    File not foundrfNumErr    –51    Bad reference numberManipulating the File MarkYou can use the functions GetFPos and SetFPos to determine or alter the current position of the file mark.1GetFPosYou can use the GetFPos function to determine the current position of the file mark before reading from or writing to an open file.FUNCTION GetFPos (refNum: Integer; VAR filePos: LongInt): OSErr;refNum    The file reference number of an open file.filePos    On output, the current position of the mark.DESCRIPTIONGetFPos returns, in the filePos parameter, the current position of the file mark for the specified open file. The position value is 0-based, so that the value of filePos for a file whose mark is positioned at the beginning of the file is 0.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openrfNumErr    –51    Bad reference numbergfpErr    –52    Error during GetFPos1SetFPosYou can use the SetFPos function to position the file mark before reading from or writing to an open file.FUNCTION SetFPos (refNum: Integer; posMode: Integer;                         posOff: LongInt): OSErr;refNum    The file reference number of an open file.posMode    The positioning mode.posOff    The positioning offset.DESCRIPTIONSetFPos sets the file mark of the specified file. The posMode parameter indicates how to position the mark; it must contain one of the following values:CONST                    fsAtMark                = 0;        {at current mark}                    fsFromStart                = 1;        {set mark relative to beginning of file}                    fsFromLEOF                = 2;        {set mark relative to logical end-of-file}                    fsFromMark                = 3;        {set mark relative to current mark}If you specify fsAtMark, the mark is left wherever it’s currently positioned and the posOff parameter is ignored. The other three constants let you position the mark relative to either the beginning of the file, the logical end-of-file, or the current mark. If you specify one of these three constants, you must also pass in posOff a byte offset (either positive or negative) from the specified point.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openeofErr    –39    End-of-fileposErr    –40    Attempt to position before start of filerfNumErr    –51    Bad reference numberManipulating the End-of-FileYou can use the two functions GetEOF and SetEOF to determine or alter the logical end-of-file of an open file.1GetEOFYou can use the GetEOF function to determine the current logical end-of-file of an open file.FUNCTION GetEOF (refNum: Integer; VAR logEOF: LongInt): OSErr;refNum    The file reference number of an open file.logEOF    On output, the logical end-of-file.DESCRIPTIONGetEOF returns, in the logEOF parameter, the logical end-of-file of the specified file.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openrfNumErr    –51    Bad reference numberSEE ALSOFor a description of the logical and physical end-of-file, see the section “File Access Characteristics.”1SetEOFYou can use the SetEOF function to set the logical end-of-file of an open file.FUNCTION SetEOF (refNum: Integer; logEOF: LongInt): OSErr;refNum    The file reference number of an open file.logEOF    The logical end-of-file.DESCRIPTIONSetEOF sets the logical end-of-file of the specified file. If you attempt to set the logical end-of-file beyond the physical end-of-file, the physical end-of-file is set to one byte beyond the end of the next free allocation block; if there isn’t enough space on the volume, no change is made, and SetEOF returns dskFulErr as its function result. If the logEOF parameter is 0, all space occupied by the file on the volume is released.RESULT CODESnoErr    0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writingSEE ALSOFor a description of the logical and physical end-of-file, see the section “File Access Characteristics.”FSSpec RoutinesThe File Manager includes a set of file and directory manipulation routines that accept FSSpec records as parameters. Depending on the requirements of your application and on the environment in which it is running, you may be able to accomplish all your file and directory operations by using these routines.Before calling any of these routines, however, you should ensure that they are available in the operating environment by calling the Gestalt function. (See “Testing for File Management Routines” for an illustration of calling Gestalt.) If these routines are not available, you can call the corresponding HFS routines.Opening, Creating, and Deleting FilesThe File Manager provides FSSpec routines that allow you to open, close, and delete files.1FSpOpenDFYou can use the FSpOpenDF function to open a file’s data fork.FUNCTION FSpOpenDF (spec: FSSpec; permission: SignedByte;                            VAR refNum: Integer): OSErr;spec    An FSSpec record specifying the file whose data fork is to be opened.permission    A constant indicating the desired file access permissions. See the list of constants in the description that follows.refNum    A reference number of an access path to the file’s data fork.DESCRIPTIONThe FSpOpenDF function opens the data fork of the file specified by the spec parameter and returns an access path reference number to that fork in the refNum parameter. You can pass that reference number as a parameter to any of the high-level file access routines. The permission parameter specifies the kind of access path permission you want. You can specify one of these constants:CONST                fsCurPerm                    =    0;        {exclusive read/write permission, if }                                                { available; otherwise exclusive read}                fsRdPerm                    =    1;        {exclusive read permission}                fsWrPerm                    =    2;        {exclusive write permission}                fsRdWrPerm                    =    3;        {exclusive read/write access}In most cases, you can simply set the permission parameter to fsCurPerm. Some applications request fsRdWrPerm, to ensure that they can both read from and write to a file. RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenametmfoErr    –42    Too many files openfnfErr    –43    File not foundopWrErr    –49    File already open for writingdirNFErr    –120    Directory not found or incomplete pathname1FSpCreateYou can use the FSpCreate function to create a new file.FUNCTION FSpCreate (spec: FSSpec; creator: OSType;                             fileType: OSType; scriptTag: ScriptCode):                             OSErr;spec    An FSSpec record specifying the file to be created.creator    The creator of the new file.fileType    The file type of the new file.scriptTag    The code of the script system in which the file’s name is to be displayed. If you have established the name and location of the new file using either the StandardPutFile or CustomPutFile procedure, specify the script code returned in the reply record. (See the chapter “The Standard File Package” in this volume for a description of StandardPutFile and CustomPutFile.) Otherwise, specify the system script by setting the scriptTag parameter to the value smSystemScript.DESCRIPTIONThe FSpCreate function creates a new file (both forks) with the specified type, creator, and script code. The new file is unlocked and empty. The date and time of creation and last modification are set to the current date and time.SPECIAL CONSIDERATIONSFiles created using FSpCreate are not automatically opened. If you want to write data into the new file, you must first open the file using a file access routine (such as FSpOpenDF).RESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamewPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and version1FSpDeleteYou can use the FSpDelete function to delete files and directories.FUNCTION FSpDelete (spec: FSSpec): OSErr;spec    An FSSpec record specifying the file or directory to delete.DESCRIPTIONThe FSpDelete function removes a file or directory. If the specified target is a file, both forks of the file are deleted. In addition, if a file ID reference for the specified file exists, that file ID reference is removed.SPECIAL CONSIDERATIONSA file must be closed before FSpDelete can delete it. Similarly, a directory must be empty before FSpDelete can delete it. If you attempt to delete an open file or a nonempty directory, FSpDelete returns the result code fBsyErr.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockfBsyErr    –47    File busy, directory not empty, or working        directory control block opendirNFErr    –120    Directory not found or incomplete pathnameExchanging the Data in Two FilesThe function FSpExchangeFiles allows you to exchange the data in two files. If the FSSpec routines are not available, you can call the low-level HFS routine PBExchangeFiles, which is described in the chapter “The FIle Manager” in this volume.1FSpExchangeFilesYou can use the FSpExchangeFiles function to exchange the data stored in two files on the same volume.FUNCTION FSpExchangeFiles (source: FSSpec; dest: FSSpec): OSErr;source    The file whose contents and file information are placed into the file specified by the dest parameter.dest    The file whose contents and file information are placed into the file specified by the source parameter.DESCRIPTIONFSpExchangeFiles swaps the data in two files by changing the information in the volume’s catalog and, if the files are open, in the file control blocks. You should use FSpExchangeFiles when updating an existing file, so that if the file is being tracked through its file ID, the ID remains valid. FSpExchangeFiles changes the fields in the catalog entries that record the location of the data and the modification dates. It swaps both the data forks and the resource forks.FSpExchangeFiles works on either open or closed files. If either file is open, FSpExchangeFiles updates any file control blocks associated with the file. Exchanging the contents of two files requires essentially the same access permissions as opening both files for writing.FSpExchangeFiles does not require that file ID references exist for the files being exchanged.SPECIAL CONSIDERATIONSThe files whose data is to be exchanged must both reside on the same volume. If they do not, FSpExchangeFiles returns the result code diffVolErr.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundioErr    –36    I/O errorfnfErr    –43    File not foundfLckdErr    –45    File lockedvolOfflinErr    –53    Volume is off linewrgVolTypeErr    –123    Not an HFS volumenotAFileErr    –1302    Specified file is a directorydiffVolErr    –1303    Files are on different volumessameFileErr    –1306    Source and destination are the sameCreating File System SpecificationsThe FSMakeFSSpec function allows you to create FSSpec records.1FSMakeFSSpecYou can use the FSMakeFSSpec function to create an FSSpec record for a file or directory.FUNCTION FSMakeFSSpec (vRefNum: Integer; dirID: LongInt;                                 fileName: Str255; VAR spec: FSSpec):                                 OSErr;vRefNum    A volume specification. This parameter can contain a volume reference number, a working directory reference number, a drive number, or 0 (to specify the default volume).dirID    A directory specification. This parameter is usually the parent directory ID of the target object. If the directory is sufficiently specified by either the vRefNum or fileName parameter, dirID can be 0. If you explicitly specify dirID (that is, if it is any value other than 0), and if vRefNum is a working directory reference number, dirID overrides the directory ID included in vRefNum. If the fileName parameter is an empty string, FSMakeFSSpec creates an FSSpec record for a directory specified by either the dirID or vRefNum parameter.fileName    A full or partial pathname. If it is a full pathname, FSMakeFSSpec ignores both the vRefNum and dirID parameters. A partial pathname might identify only the final target, or it might include one or more parent directory names. If fileName is a partial pathname, then vRefNum, dirID, or both must be valid.spec    A file-system specification to be filled in by FSMakeFSSpec.DESCRIPTIONFSMakeFSSpec fills in the fields of the spec parameter using the information contained in the other three parameters. Call FSMakeFSSpec whenever you want to create an FSSpec record.You can pass the input to FSMakeFSSpec in any one of four ways. See the chapter “The File Manager” for information about the way FSMakeFSSpec interprets its input.If the specified volume is mounted and the specified parent directory exists, but the target file or directory doesn’t exist in that location, FSMakeFSSpec fills in the record and then returns fnfErr instead of noErr. The record is valid, but it describes a target that doesn’t exist. You can use the record for other operations, such as creating a file with the FSpCreate function.In addition to the result codes that follow, FSMakeFSSpec can return a number of different File Manager error codes. If your application receives any result code other than noErr or fnfErr, FSMakeFSSpec returns a NIL FSSpec record.RESULT CODESnoErr    0    No errornsvErr    –35    Volume doesn’t existfnfErr    –43    File or directory does not exist        (FSSpec is still valid)Volume Access RoutinesThis section describes the high-level volume access routines. Unless your application has very specialized needs, you should be able to manage all volume access using the routines described in this section. In fact, most applications are likely to need only the FlushVol function described in “Updating Volumes.”When you call one of these routines, you specify a volume by a volume reference number (which you can obtain, for example, by calling the GetVInfo function, or from the reply record returned by the Standard File Package). You can also specify a volume by name, but this is generally discouraged, because there is no guarantee that volume names will be different.Updating VolumesWhen you close a file, you should call FlushVol to ensure that any changed contents of the file are written out to disk.1FlushVolYou can use the FlushVol function to write out the contents of the volume buffer and update information about the volume.FUNCTION FlushVol (volName: StringPtr; vRefNum: Integer): OSErr;volName    A pointer to the name of a mounted volume.vRefNum    A volume reference number, a working directory reference number, a drive number, or 0 for the default volume.DESCRIPTIONOn the specified volume, the FlushVol function writes the contents of the associated volume buffer and descriptive information about the volume (if they’ve changed since the last time FlushVol was called).RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad volume nameparamErr    –50    No default volumensDrvErr    –56    No such driveObtaining a Volume Reference NumberYou can get a volume reference number from a file reference number by calling the GetVRefNum function.1GetVRefNumYou can use the GetVRefNum function to get a volume reference number from a file reference number.FUNCTION GetVRefNum (refNum: Integer; VAR vRefNum: Integer):                             OSErr;refNum    The file reference number of an open file.vRefNum    The volume reference number of the volume.DESCRIPTIONGetVRefNum returns the volume reference number of the volume containing the specified file.RESULT CODESnoErr    0    No errorrfNumErr    –51    Bad reference numberApplication Launch File RoutinesYou can call GetAppParms to determine your application’s name and the reference number of its resource file. When your application starts up, you can call CountAppFiles to determine whether any documents were selected by the user to be opened or printed. If so, you can call GetAppFiles and ClrAppFiles to process the information passed to your application by the Finder.If your application supports high-level events, you receive this information from the Finder in an Open Documents or Print Documents event.<36pt\>\x12 <8bat\>u1GetAppParmsYou can use the GetAppParms procedure to get information about the current application and about files selected by the user for opening or printing.PROCEDURE GetAppParms    (VAR apName: Str255; VAR apRefNum: Integer;                             VAR apParam: Handle);apName    On output, the name of the calling application.apRefNum    On output, the reference number of the application’s resource file.apParam    On output, a handle to the Finder information about files to open or print.DESCRIPTIONGetAppParms returns information about the current application. You can call GetAppParms at application launch time to determine which files, if any, the user has selected in the Finder for opening or printing. You can call GetAppParms at any time to determine the current application’s name and the reference number of the application’s resource fork.GetAppParms returns the application’s name in the apName parameter and the reference number of its resource fork in the apRefNum parameter. A handle to the Finder information is returned in apParam. This information consists of a word that encodes the message or action to be performed, a word that indicates how many files to process, and a list of Finder information about each such file. The Finder information has the structure of an AppFiles record, except that the filename occupies only as many bytes as are required to hold the name (padded to an even number of bytes, if necessary). In general, it is easier to use the GetAppFiles procedure to access the Finder information.SPECIAL CONSIDERATIONSIf you simply want to determine the application’s resource file reference number, you can call the Resource Manager function CurResFile when your application starts up.If you need more extensive information about the application than is provided by GetAppParms, you can use the Process Manager function GetCurrentProcess.ASSEMBLY-LANGUAGE INFORMATIONYou can get the application’s name, reference number, and handle to the Finder information directly from the global variables CurApName, CurApRefNum, and AppParmHandle.1CountAppFilesYou can use the CountAppFiles procedure to determine how many documents (if any) the user has selected at application launch time for opening or printing.PROCEDURE CountAppFiles (VAR message: Integer;                                  VAR count: Integer);message    The action to be performed on the selected files.count    The number of files selected.DESCRIPTIONCountAppFiles deciphers the Finder information passed to your application and returns information about the files that were selected when your application was started up. On exit, the count parameter contains the number of selected files and the message parameter contains an integer that indicates whether the files are to be opened or printed. The message parameter contains one of these constants:CONST                appOpen            =    0;        {open the document(s)}                appPrint            =    1;        {print the document(s)}1GetAppFilesYou can use the GetAppFiles procedure to retrieve information about each file selected at application startup for opening or printing.PROCEDURE GetAppFiles (index: Integer; VAR theFile: AppFile);index    The index of the file whose information is returned.theFile    A structure containing the returned information.DESCRIPTIONGetAppFiles returns information about a file that was selected when your application was started up (as listed in the Finder information). The index parameter indicates the file for which information should be returned; it must be between 1 and the number returned by CountAppFiles, inclusive.1ClrAppFilesYou can use the ClrAppFiles procedure to notify the Finder that you have processed the information about a file selected for opening or printing at application startup.PROCEDURE ClrAppFiles (index: Integer);index    The index of the file whose information is to be cleared.DESCRIPTIONClrAppFiles changes the Finder information passed to your application about the specified file so that the Finder knows you’ve processed the file. The index parameter must be between 1 and the number returned by CountAppFiles, inclusive. You should call ClrAppFiles for every document your application opens or prints, so that the information returned by CountAppFiles and GetAppFiles is always correct. ClrAppFiles sets the file type in the Finder information to 0.Summary of File ManagementConstantsCONST        {Gestalt constants}    gestaltFSAttr                                =    'fs  ';            {file system attributes selector}    gestaltHasFSSpecCalls                                =    1;            {supports FSSpec records}    gestaltStandardFileAttr                                =    'stdf';            {Standard File attributes selector}    gestaltStandardFile58                                =    0;            {supports StandardPutFile etc.}    gestaltFindFolderAttr                                =    'fold';            {FindFolder attributes selector}    gestaltFindFolderPresent                                =    0;            {FindFolder is present}    {permissions for opening files}    fsCurPerm                        =    0;            {exclusive read/write permission, if }                                            { available; otherwise exclusive read}    fsRdPerm                        =    1;            {exclusive read permission}    fsWrPerm                        =    2;            {exclusive write permission}    fsRdWrPerm                        =    3;            {exclusive read/write access}    {file mark positioning modes}    fsAtMark                        =    0;            {at current mark}    fsFromStart                        =    1;            {set mark relative to beginning of file}    fsFromLEOF                        =    2;            {set mark relative to logical end-of-file}    fsFromMark                        =    3;            {set mark relative to current mark}    rdVerify                        =    64;            {add to above for read-verify}    {messages from CountAppFiles}    appOpen                        =    0;            {open the document(s)}    appPrint                        =    1;            {print the document(s)}Data TypesFile System Specification RecordTYPE FSSpec                             =    RECORD                vRefNum:                    Integer;                {volume reference number}        parID:                    LongInt;                {directory ID of parent directory}        name:                    Str63;                {filename or directory name}    END;    FSSpecPtr                        =     ^FSSpec;    FSSpecHandle                        =     ^FSSpecPtr;Standard File Reply RecordTYPE    StandardFileReply                        =    RECORD        sfGood:                    Boolean;                {TRUE if user did not cancel}        sfReplacing:                    Boolean;                {TRUE if replacing file with same name}        sfType:                    OSType;                {file type}        sfFile:                    FSSpec;                {selected item}        sfScript:                    ScriptCode;                {script of selected item’s name}        sfFlags:                    Integer;                {Finder flags of selected item}        sfIsFolder:                    Boolean;                {selected item is a folder}        sfIsVolume:                    Boolean;                {selected item is a volume}        sfReserved1:                    LongInt;                {reserved}        sfReserved2:                    Integer;                {reserved}    END;Application Files RecordTYPE AppFile                             =    RECORD        vRefNum:                    Integer;                {working directory reference number}        fType:                    OSType;                {file type}        versNum:                    Integer;                {version number; ignored}        fName:                    Str255;                {file name}    END;    SFTypeList                        =    ARRAY[0..3] OF OSType;    FileFilterProcPtr                        =    ProcPtr;            {file filter function}File Identification RoutinesOpening FilesPROCEDURE StandardGetFile    (fileFilter: FileFilterProcPtr;numTypes: Integer; typeList: SFTypeList; VAR reply: StandardFileReply);Saving FilesPROCEDURE StandardPutFile    (prompt: Str255; defaultName: Str255; VAR reply: StandardFileReply);File Access RoutinesReading, Writing, and Closing FilesFUNCTION FSRead    (refNum: Integer; VAR count: LongInt; buffPtr: Ptr): OSErr;FUNCTION FSWrite    (refNum: Integer; VAR count: LongInt; buffPtr: Ptr): OSErr;FUNCTION FSClose    (refNum: Integer): OSErr;Manipulating the File MarkFUNCTION GetFPos    (refNum: Integer; VAR filePos: LongInt): OSErr;FUNCTION SetFPos    (refNum: Integer; posMode: Integer; posOff: LongInt): OSErr;Manipulating the End-of-FileFUNCTION GetEOF    (refNum: Integer; VAR logEOF: LongInt): OSErr;FUNCTION SetEOF    (refNum: Integer; logEOF: LongInt): OSErr;File System Specification RoutinesOpening, Creating, and Deleting FilesFUNCTION FSpOpenDF    (spec: FSSpec; permission: SignedByte; VAR refNum: Integer): OSErr;FUNCTION FSpCreate    (spec: FSSpec; creator: OSType; fileType: OSType; scriptTag: ScriptCode): OSErr;FUNCTION FSpDelete    (spec: FSSpec): OSErr;Exchanging the Data in Two FilesFUNCTION FSpExchangeFiles    (source: FSSpec; dest: FSSpec) : OSErr;Creating File System SpecificationsFUNCTION FSMakeFSSpec    (vRefNum: Integer; dirID: LongInt;fileName: Str255; VAR spec: FSSpec): OSErr;Volume Access RoutinesUpdating VolumesFUNCTION FlushVol    (volName: StringPtr; vRefNum: Integer): OSErr;Obtaining Volume InformationFUNCTION GetVInfo    (drvNum: Integer; volName: StringPtr; VAR vRefNum: Integer; VAR freeBytes: LongInt): OSErr;FUNCTION GetVRefNum    (refNum: Integer; VAR vRefNum: Integer): OSErr;Application Launch File RoutinesObtaining Information About an ApplicationPROCEDURE GetAppParms    (VAR apName: Str255; VAR apRefNum: Integer; VAR apParam: Handle);Obtaining Information About Files to be Opened or PrintedPROCEDURE CountAppFiles    (VAR message: Integer; VAR count: Integer);PROCEDURE GetAppFiles    (index: Integer; VAR theFile: AppFile);PROCEDURE ClrAppFiles    (index: Integer);Global VariablesAppParmHandle    Handle to Finder informationCurApName    Name of current application (length byte followed by up to 31 characters)CurApRefNum    Reference number of current application’s resource file (word)Result CodesnoErr    0    No errordirFulErr     –33    File directory fulldskFulErr     –34    All allocation blocks on the volume are fullnsvErr    –35    Volume not foundioErr    –36    I/O errorbdNamErr    –37    Bad filename or volume namefnOpnErr     –38    File not openeofErr    –39    Logical end-of-file reachedposErr     –40    Attempt to position mark before start of filetmfoErr    –42    Too many files openfnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockfBsyErr     –47    File is busy; one or more files are open; directory not         empty or working directory control block is opendupFNErr     –48    A file with the specified name and version number        already existsopWrErr    –49    File already open for writingparamErr    –50    Parameter errorrfNumErr     –51    Reference number specifies nonexistent access pathgfpErr     –52    Error during GetFPosvolOfflinErr    –53    Volume is off linepermErr     –54    Attempt to open locked file for writingvolOnLinErr    –55    Specified volume is already mounted and on-linensDrvErr     –56    Specified drive number doesn’t match any number        in the drive queuenoMacDskErr     –57    Volume lacks Macintosh-format directoryextFSErr    –58    External file systemfsRnErr     –59    Problem during renamebadMDBErr     –60    Bad master directory blockwrPermErr    –61    Read/write permission doesn’t allow writingdirNFErr    –120    Directory not foundwrgVolTypeErr    –123    Not an HFS volumenotAFileErr    –1302    Specified file is a directorydiffVolErr    –1303    Files are on different volumessameFileErr    –1306    Files are the sameIndexAaliasdefined9allocation blockssize5AppFile data type38.See also application files record38application files record38Bblockslogical4Cclumpsdefined6creating14creation dates handled by FSpExchangeFiles24Ddata fork2dialog boxesfor saving and opening files39 to ??directoryrootdefined8disk cache7document recorddefined13Eend-of-filelogical5physical5Ffile datalimitations of using Resource Manager4using the File Manager to read4using the Resource Manager to read3file forksdata fork2resource fork2file fragmentationavoiding6File Managercreating FSSpec records50 to 51exchanging contents of two files49 to 50file markdefined6file reference numberdefined6files14, 19, 24, 25closing29defined2handling File menu commands10opening15opening at application startup31reading data in newline mode7reverting to the last saved version27saving preferences33writing data to21fName field39FSMakeFSSpec function50FSpCreate function47FSpOpenDF function46fType field38HHierarchical File System (HFS)defined7Llogical blocksdefined4Mmodification dates, handled by FSpExchangeFiles24NNew Folder dialog box27, 37Oopeningfiles46PPreferences files33Rreading data from19resource fork2resource types‘'DITL' ’27Revert to Saved menu command27root directorydefined8Ssaving24saving under a new name25scriptsspecifying when creating a file47Standard File Packageopening files39 to 40reply record37 to 38saving files40StandardGetFile procedure39StandardPutFile procedure40stationery padshandled by Standard File Package38VversNum field39volumesdefined4vRefNum field38Wworking directory reference numbers13ZzzReserved2 field38zzsfFile field38zzsfFlags field38zzsfGood field37zzsfIsFolder field38zzsfIsVolume field38zzsfReplacing field37zzsfReserved1 field38zzsfScript field38zzsfType field37zzsmSystemScript38The File ManagerAbout the File Manager2-5File Manipulation2-7Directory Manipulation2-9Volume Manipulation2-10Shared Environments2-12Shared File Access Permissions2-13Directory Access Privileges2-14Remote Volume Mounting2-16Privilege Information in Foreign File Systems2-17File ID Routines2-18Identifying Files, Directories, and Volumes2-19File System Specifications2-19File IDs2-20Directory IDs2-21Volume Reference Numbers2-21Working Directory Reference Numbers2-22Names and Pathnames2-23HFS Specifications2-24Using the File Manager2-27Determining the Features of the File Manager2-27Creating File System Specification Records2-29Manipulating the Default Volume and Directory2-30Deleting Files and File Forks2-32Searching a Catalog2-33Constructing Full Pathnames2-39Determining the Amount of Free Space on a Volume2-41Sharing Volumes and Directories2-42Locking and Unlocking File Ranges2-44Data Organization on Volumes2-47Disk and Volume Organization2-48Boot Blocks2-53Master Directory Blocks2-56Volume Bitmaps2-58B*-Trees2-59Nodes2-60Node Records2-62Header Nodes2-63Map Nodes2-65Index Nodes2-66Leaf Nodes2-66Catalog Files2-66Catalog File Keys2-67Catalog File Data Records2-68Extents Overflow Files2-71Data Organization in Memory2-72The File I/O Queue2-73Volume Control Blocks2-73File Control Blocks2-77B*-Tree Control Blocks2-79The Drive Queue2-80Reference to the File Manager2-82Data Structures2-82File System Specification Record2-82Basic File Manager Parameter Block2-83HFS Parameter Block2-87Catalog Information Parameter Blocks2-96Catalog Position Records2-100Catalog Move Parameter Blocks2-100Working Directory Parameter Blocks2-102File Control Block Parameter Blocks2-103Volume Attributes Buffer2-105Volume Mounting Information Records2-106High-Level File Access Routines2-108Reading, Writing, and Closing Files2-108Manipulating the File Mark2-111Manipulating the End-of-File2-112Allocating File Blocks2-113Low-Level File Access Routines2-115Reading, Writing, and Closing Files2-116Manipulating the File Mark2-119Manipulating the End-of-File2-121Allocating File Blocks2-123Updating Files2-125High-Level Volume Access Routines2-126Unmounting Volumes2-126Updating Volumes2-127Manipulating the Default Volume2-128Obtaining Volume Information2-131Low-Level Volume Access Routines2-132Mounting and Unmounting Volumes2-132Updating Volumes2-136Obtaining Volume Information2-137Manipulating the Default Volume2-143File System Specification Routines2-147Opening Files2-147Creating and Deleting Files and Directories2-149Accessing Information about Files and Directories2-151Moving Files or Directories2-155Exchanging the Data in Two Files2-156Creating File System Specifications2-157High-Level HFS Routines2-159Opening Files2-159Creating and Deleting Files and Directories2-162Accessing Information about Files and Directories2-165Moving Files or Directories2-168Maintaining Working Directories2-170Low-Level HFS Routines2-172Opening Files2-172Creating and Deleting Files and Directories2-175Accessing Information about Files and Directories2-178Moving Files or Directories2-187Maintaining Working Directories2-189Searching a Catalog2-191Exchanging the Data in Two Files2-193Shared Environment Routines2-194Opening Files While Denying Access2-195Locking and Unlocking File Ranges2-196Manipulating Share Points2-199Controlling Directory Access2-202Mounting Volumes2-203Controlling Login Access2-206Copying and Moving Files2-209File ID Routines2-211Resolving File ID References2-212Creating and Deleting File ID References2-213Foreign File System Routines2-215Accessing Privilege Information in Foreign File Systems2-215Utility Routines2-217Obtaining Queue Headers2-217Adding a Drive2-218Obtaining File Control Block Information2-219Summary of the File Manager2-2212The File ManagerThis chapter describes how your application can use the File Manager to store and access data in files or to manipulate files, directories, and volumes. It also provides a complete description of all File Manager routines, data types, and constants.You need to read the information in this chapter if you wish to use File Manager routines other than those described in the “Introduction to File Management” chapter earlier in this volume. That chapter shows how to use the File Manager, the Standard File Package, and other system software components to handle the typical File menu commands and perform other common file-manipulation operations. This chapter addresses a number of other important file-related issues, includingn    using the low-level File Manager routinesn    locking and unlocking byte ranges in shard filesn    searching a volume for files or directories satisfying certain criterian    obtaining information about files, directories, and volumesThis chapter also addresses some advanced topics that are of use only to very specialized applications or file-system utility programs. These advanced topics includen    how the File Manager organizes file and directory data on diskn    how the File Manager organizes information in memoryTo use this chapter, you should already be familiar with the information presented in the “Introduction to File Management” chapter earlier in this volume. This chapter begins with a general introduction to the File Manager and the services it provides. Then it describesn    ways of identifying files, directories, and volumesn    file access permissionsn    directory access privilegesn    running in a shared environmentAbout the File ManagerThe File Manager is the part of the Macintosh Operating System that manages the organization, reading, and writing of data located on physical data storage devices such as disk drives. This data includes the data contained in documents, as well as other collections of data that are used to maintain the hierarchical file system (HFS) and other system software services. To accomplish these tasks, the File Manager interacts with many other components of the system software. For example, the Resource Manager uses File Manager routines when it needs to read and write resource data. Similarly, the File Manager calls the Device Manager to perform the actual reading and writing of data on a physical data storage device. In general, you’ll use the Resource Manager to read and write data in a file’s resource fork and the File Manager to read and write data in a file’s data fork. You’ll also use the File Manager to perform operations on directories and volumes.The File Manager provides a large number of routines that you can use to perform various operations on files, directories, and volumes. Which of these routines you need to use depends on the requirements of your application. Many applications simply need to open files, read and write the data in those files, and then close the files. Other applications might provide more capabilities, such as the ability to copy a file or move a file to another directory. A few file-system utilities perform even more extensive file operations and hence need to use some of the advanced routines provided by the File Manager; for example, a disk-scavenger might need to look through a volume byte-by-byte to search for pieces of a deleted file.You can often use one of several File Manager routines to accomplish a particular task. This is because many of the File Manager routines are provided in two different forms: high-level and low-level. The low-level routines generally provide the greatest control over the requested task; they are identified by the prefixes “PB” and “PBH”, indicating that they take the address of a parameter block as a parameter. The high-level routines are always defined in terms of low-level routines; they are identified by prefixes such as “FSp” or “H” indicating how you identify files or directories using those routines, or by no special prefix at all.Using the high-level routines, you pass  information to a routine through the routine’s parameters. A high-level routine has as many parameters as are necessary to pass the information required by the routine.Using low-level routines, you pass information to the routine by filling in fields in a parameter block and then passing the address of the parameter block to the routine. In certain cases, a low-level routine uses more fields in the parameter block than there are parameters in the corresponding high-level routime. As a result, those low-level routines can be used to perform more advanced operations or to provide more extensive information than the corresponding high-level routines. This is the principal reason you might choose to use a particular low-level routine instead of a corresponding high-level routine.If you use the low-level File Manager routines, be sure to clear all unused fields of the parameter block.<36pt\>\x12 <8bat\>uLow-level routines also accept a parameter indicating whether you want the routine to be executed synchronously or asynchronously. If you request synchronous execution, control does not return to your application until the routine has executed. This allows you to test the routine’s result code to see whether the routine executed successfully. If it did, your code can continue by performing other operations that depend on the successful completion of that routine.If you request asynchronous execution, the call is put into a file I/O queue and control returns to your application immediately—possibly even before the actual I/O is completed. The File Manager takes requests from the queue one at a time and processes them; meanwhile, your application is free to work on other things. Routines that are executed asynchronously return control to your application with the result code noErr as soon as the call is placed in the file I/O queue. This isn’t an indication of successful call completion, but simply indicates that the call was successfully queued. To determine when the call is actually completed, you can inspect the ioResult field of the parameter block; this field is set to a positive number when the call is made, and receives the actual result code upon completion of the call.Although you can always specify that you want a low-level routine to execute asynchronously, the device driver for the device on which the target file, directory, or volume resides might not support asynchronous operations. For example, the current implementation of the SCSI Manager provides synchronous execution only. The Sony disk driver and AppleShare server software do however support asynchronous operation.<36pt\>\x12 <8bat\>uThe following sections describe the various capabilities of the File Manager. For full details on any of the routines mentioned in these sections, see the descriptions given in the Reference section later in this chapter.File ManipulationThe File Manager provides a number of routines that allow you to manipulate files. You can open a file fork, read and write the data in it, adjust its logical end-of-file, set the file mark, allocate blocks to a file, and close a file.In order to manipulate the data contained in a file, you first need to open the file. You can open a file using one of several routines, depending on whether you want to use low-level or high-level routines and how you identify the file to open. Table 2-1 lists the file-opening routines. Routines for opening file forksFSSpec     HFS High-Level    HFS Low-Level    DescriptionFSpOpenDF    HOpenDF    PBHOpenDF    Open a file’s data fork.FSpOpenRF    HOpenRF    PBHOpenRF    Open a file’s resource fork.    HOpen    PBHOpen    Open a driver or file data fork.All the high-level FSSpec routines require you to specify a file using a file system specification record. All the HFS routines, whether high- or low-level, require you to specify a file by its volume, directory, and name.No matter which routine you use to open a file, you need to specify a file access permission that governs the kind of access you can have to that file. You can specify one of these constants:CONST                fsCurPerm                    =    0;        {exclusive read/write permission, if }                                                { available; otherwise exclusive read}                fsRdPerm                    =    1;        {read-only permission}                fsWrPerm                    =    2;        {exclusive write permission}                fsRdWrPerm                    =    3;        {exclusive read/write permission}                fsRdWrShPerm                    =    4;        {shared read/write permission}You can request permission to read only, write only (rarely done), or both read and write. Note that there are two types of read/write permission—exclusive and shared. Applications generally want exclusive read/write permission, so they can safely read and alter portions of a file. If your application requests and is granted exclusive read/write permission, no other acccess paths will be granted permission to write to the file; other users may however be granted read permission on the file.A second type of read/write permission allows multiple access paths to be open for writing. If you’ll be using only a portion, or range, of a file, you can request shared read/write permission. See the shared environment routines described below for a description of byte-range locking in shared files.When you successfully open a file fork, you receive a file reference number that uniquely identifies the open file. You can pass that number to the File Manager routines that allow you to manipulate open files. Table 2-2 lists the routines that operate on open files.Routines for operating on open file forksHigh-Level    Low-Level    DescriptionFSRead    PBRead    Read bytes from an open file fork.FSWrite    PBWrite    Write bytes to an open file fork.FSClose    PBClose    Close an open file fork.GetFPos    PBGetFPos    Get the position of the file mark.SetFPos    PBSetFPos    Set the position of the file mark.GetEOF    PBGetEOF    Get the current logical end-of-file.SetEOF    PBSetEOF    Set the current logical end-of-file.Allocate    PBAllocate    Add allocation blocks to a file fork.AllocContig    PBAllocContig    Add contiguous allocation blocks to a file fork.    PBFlushFile    Update the disk contents of a file fork.GetVRefNum        Get volume reference number of an open file.The File Manager provides a number of routines that allow you to operate on closed files. You can create, delete, get and set information, and lock and unlock files. You can also move files within a volume and exchange the data in two files. Table 2-2 lists these routines.Routines for operating on closed filesFSSpec     HFS High-Level    HFS Low-Level    DescriptionFSpCreate    HCreate    PBHCreate    Create both forks of a new file.FSpDelete    HDelete    PBHDelete    Delete both forks of a file.FSpGetFInfo    HGetFInfo    PBHGetFInfo    Get a file’s Finder information.FSpSetFInfo    HSetFInfo    PBHSetFInfo    Set a file’s Finder information.FSpSetFLock    HSetFLock    PBHSetFLock    Lock a file.FSpRstFLock    HRstFLock    PBHRstFLock    Unlock a file.FSpCatMove    CatMove    PBCatMove    Move a file or directory             within a volume.FSpRename    HRename    PBHRename    Rename a file or directory.        PBGetCatInfo    Get information about a file            or directory.        PBSetCatInfo    Set information about a file            or directory.You can exchange the data in two files using the FSpExchangeFiles and PBExchangeFiles functions. If you need to create a file system specification record, you can use the FSMakeFSSpec or PBMakeFSSpec functions.Directory ManipulationThe File Manager provides a number of routines that allow you to manipulate directories. For example, you can create and delete directories, get information about a directory, and move and rename directories. The directory manipulation routines are listed in Table 2-2.Routines for operating on directoriesFSSpec     HFS High-Level    HFS Low-Level    DescriptionFSpDirCreate    DirCreate    PBDirCreate    Create a directory.FSpDelete    HDelete    PBHDelete    Delete a directory.FSpGetFInfo    HGetFInfo    PBHGetFInfo    Get Finder information for            a directory.FSpSetFInfo    HSetFInfo    PBHSetFInfo    Set Finder information for            a directory.FSpSetFLock    HSetFLock    PBHSetFLock    Lock a directory.FSpRstFLock    HRstFLock    PBHRstFLock    Unlock a directory.FSpCatMove    CatMove    PBCatMove    Move a file or directory             within a volume.FSpRename    HRename    PBHRename    Rename a file or directory.        PBGetCatInfo    Get information about a file            or directory.        PBSetCatInfo    Set information about a file            or directory.The File Manager includes a number of routines that allow you to manipulate working directories, listed in Table 2-2. Most applications do not need to use working directories.Routines for manipulating working directoriesHigh-Level     Low-Level    DescriptionOpenWd    PBOpenWd    Open a working directory.CloseWD    PBCloseWD    Close a working directory.GetWDInfo    PBGetWDInfo    Get information about a working directory.Volume ManipulationThe File Manager provides a number of routines that allow you to manipulate volumes. For example, you can obtain information about a mounted volume, update the information on a volume, unmount a mounted volume or place it off-line, and so forth. Most applications don’t need to access volumes explicitly. Most of the inserting and ejecting of disks is handled by the Standard File Package and the Finder.When the Event Manager function WaitNextEvent (or GetNextEvent) receives a disk-inserted event, it calls the Desk Manager function SystemEvent. SystemEvent calls the File Manager function PBMountVol, which attempts to mount the volume on the disk. The result of the PBMountVol call is put into the high-order word of the event message and the drive number is put into its low-order word. If the result code indicates that an error occurred, you’ll need to call the Disk Initialization Package routine DIBadMount to allow the user to initialize or eject the volume.After a volume has been mounted, your application can call GetVInfo, which returns the name, the amount of unused space, and the volume reference number. Given a file reference number, you can get the volume reference number of the volume containing that file by calling either GetVRefNum or GetFCBInfo.An application can unmount or place off-line any volumes that aren’t currently being used. To unmount a volume, call UnmountVol, which flushes a volume (by calling FlushVol) and releases all of the memory used for it. To place a volume off-line, call PBOffLine, which flushes a volume and releases all of the memory used for it except for the volume control block. Off-line volumes are placed on-line by the File Manager as needed, but your application must remount any unmounted volumes it wants to access. The File Manager itself may place volumes off-line during its normal operation.To protect against data loss due to power interruption or unexpected disk ejection, you should periodically call FlushVol (probably after each time you close a file), which writes the contents of the volume buffer and all access path buffers (if any) to the volume and updates the descriptive information contained on the volume.Whenever your application is finished with a disk, or when the user chooses Eject from a menu, call the Eject function. Eject calls FlushVol, places the volume off-line, and then physically ejects the volume from its drive.If you would like all File Manager calls to apply to a particular volume, you can specify that volume as the default volume. You can use the HGetVol (or GetVol) function to determine the name and volume reference number of the default volume, and the SetVol function to change the default to any mounted volume.Normally, volume initialization and naming is handled by the Disk Initialization Package. If you want to initialize a volume explicitly or erase all files from a volume, you can call the Disk Initialization Package directly. When you want to change the name of a volume, call the HRename function.Table 2-6 summarizes the volume manipulation routines. Most of these routines require you to specify a volume either by name or by volume reference number.Routines for operating on volumesHigh-Level     Low-Level    Description    PBMountVol    Mount a volume.UnmountVol    PBUnmountVol    Unmount a volume.Eject    PBEject    Eject a volume.    PBOffLine    Place a volume off-line.FlushVol    PBFlushVol    Update a volume.GetVol    PBGetVol    Get the default volume.HGetVol    PBHGetVol    Get the default volume.SetVol    PBSetVol    Set the default volume.HSetVol    PBHSetVol    Set the default volume.GetVInfo    PBGetVInfo    Get information about a volume.    PBSetVInfo    Set information about a volume.    PBHGetVolParms            Determine capabilities of a volume.    PBCatSearch    Search a volume for files or directories        satifying certain criteria.Shared EnvironmentsAny operating environment that supports multiple users and multiple access to data or applications is known as a shared environment. A shared environment can be a number of workstations attached to a network, as well as a single workstation executing a multiuser operating system such as A/UX. The File Manager supports access both to locally mounted volumes and to volumes that are located on devices attached to remote machines on a network. For example, AppleShare, Apple’s file-server application, allows users to share data, applications, and disk storage over a network. System software version 7.0 introduced File Sharing, a local version of AppleShare that allows users to make some or all of the files on a volume available over the network.It is a virtual certainty that some users will run your application in a shared environment. The File Manager, Chooser, and other system software components cooperate to make access to remote volumes largely transparent to your application. As a result, most applications do not need to accommodate shared environments explicitly. You can read and write files, for instance, regardless of whether they are located on a local or a remote volume.If your application performs certain operations on files, however, you might be able to save considerable time by using special shared environment routines. Suppose, for example, that you want to copy a file to another directory on a volume. In the general case, you handle this by reading a buffer of data from the source file and then writing it to the destination file. If the source and destination volume is remote, however, this technique might involve copying a lot of data over the network. To optimize remote file copying, the File Manager provides the PBHCopyFile function, which copies a remote file without sending the data across the network. Similarly, the PBHMoveRename function allows you to move and optionally rename a file located on a remote volume.The File Manager provides routines that allow you to control other aspects of a shared environment, includingn    providing multiple users with shared read/write access to files.n    locking and unlocking byte ranges within a file to ensure exclusive access to data during updates.n    enabling and disabling sharing on local volumes and directories.n    getting and setting access privileges for directories.n    determining volume mounting and login information so that any volume can be unmounted and remounted easily.The following sections describe these capabilities.Shared File Access PermissionsIn a shared environment, files can be shared at a file or sub-file level. At a file level, a project schedule could be read by many users simultaneously but updated by only one user at a time. At a sub-file level, different records of a data base file could be updated by several users at the same time.The access modes provided by the standard file opening routines prove insufficient for sharing files. Two additional open functions, PBHOpenDeny and PBHOpenRFDeny, allow the ability to deny access as well. The access modes are cumulative, combining to form the access currently available for a file. For instance, if the first open denies reading to others, and a second denies writing, both reading and writing are then denied for the file.You specify deny modes by setting bits in the ioDenyModes field of the parameter block passed to PBHOpenDeny or PBHOpenRFDeny. Currently four bits of this field are meaningful:Bit    Meaning0    If set, request read permission.1    If set, request write permission.4    If set, deny other readers to this file.5    If set, deny other writers to this file.The combination of access and deny requests allows four common opening possibilities:n    Browsing access.  You request browsing access by specifying both read and deny-write modes (ioDenyModes set to $0021). Browsing access is traditional read-only access; it permits multiple readers but no writers. This access mode is useful for shared files that do not change often, such as help files, configuration files, and dictionaries.n    Exclusive access. You request exclusive access by specifying both read and write access and both deny-read and deny-write access (ioDenyModes set to $0033). Most applications that are not specifically designed to share file data use this permission. An exclusive access open call will succeed only if there are no existing paths to the file. If successful, all future attempts to establish access paths to the file will be denied until the exclusive-access path is closed.n    Single writer with multiple readers access. You request single writer with multiple reader access by specifying both read and write access and deny-write access (ioDenyModes set to $0023). This access method allows additional users to gain read-only access to browse a document being modified by the initial writer. The writer’s application is responsible for range-locking the file (by calling PBLockRange) before writing to it, to protect the readers from reading when the file is inconsistent.n    Shared access. You request shared access by specifying both read and write access (ioDenyModes set to $0003). Shared access should be used by applications that support full multi-user access to its documents. Range-locking is needed to prevent other users from accessing information undergoing change. Each user must also check for and hanfdle any errors that result from other users’ access. Some applications might prefer to use a semaphore to flag records in the document as checked out, rather than use range-locking exclusively.You can open a file using the deny modes described here or the original file access permissions described in “File Manipulation” on page 2-7. If you use the original permissions to open a file located in a shared directory, the File Manager translates those permissions into the corresponding deny modes. The basic rule followed in this translation is to allow a single writer or multiple readers, but not both. The translation from the original permissions to the deny mode permissions is shown in Table 2-7.Access mode translation    HFS permissions    Deny-mode permissions    fsCurPerm    Exclusive access, or browsing access if exclusive        access is unavailable.    fsRdPerm    Browsing access.    fsWrPerm    Exclusive access, or browsing access if exclusive        access is unavailable.    fsRdWrPerm    Exclusive access, or browsing access if exclusive        access is unavailable.    fsRdWShrPerm    Shared access.Notice that fsCurPerm, fsRdWrPerm, and fsWrPerm are retried as read-only if exclusive access is not available. Directory Access PrivilegesAppleShare allows users to assign  directory access privileges to individual directories, controlling who has access to the files and folders in the directory. A directory may be kept private, shared by a group of registered users, or shared with all users on the network.Users are organized into groups. Users can belong to more than one group. Information about users and their privileges is maintained by AppleShare. Each directory has access privileges assigned for each of these three classifications of users: owner, group, and everyone. The following privileges can be assigned.n    See Folders. A user with this access privilege can see other directories in the specified directory. (Also called search privilege.)n    See Files. A user with this access privilege can see the icons and open documents or applications in that directory as well. (Also called read privilege.)n    Make Changes. A user with this access privilege can create, modify, rename, or delete any file or directory contained in the specified directory. Directory deletion requires additional privileges. It is possible to have Make Changes privileges without also having See Folders or See Files privileges; this would allow users to put items into a directory but not view the contents of that directory. (Also called write privilege.)For instance, a user might assign privileges to a particular directory allowing the owner to read, write, and search the directory, and allowing everyone else (whether in the group or not) only to search the directory.On directories shared using File Sharing, you can also assign blank access privileges, where the File Manager ignores any other access privileges and uses the access privileges of the directory’s parent. On the local machine, directories in a shared area have blank access privileges, until set otherwise.You can use the PBHGetDirAccess and PBHSetDirAccess functions to determine and change the access privileges for a directory. The access privileges are passed in the four-byte ioACAccess field of the accessParam variant of the HFS parameter block passed to these two functions. The four bytes are interpreted separately; byte 0 is the high-order byte:Byte    Meaning0    User’s access privileges1    Everyone’s access privileges2    Group’s access privileges3    Owner’s access privilegesThe bits in each byte encode access privilege information, as illustrated in Figure 2-1. (The high-order byte is on top and high-order bit is on the left.) Note that the User’s privileges byte also indicates whether the user owns the directory and whether the directory has blank access privileges.    Access privileges information in the ioACAccess fieldIf bit 31 is set, then the user is the owner of the specified directory. If bit 28 is set, the specified directory has blank access privileges. If bit 28 is clear, the three low-order bits of each byte encode the write, read, and search privileges, respectively. If one of these bits is set, the directory privileges permit the indicated access to the specified individual.The three low-order bits of the byte encoding the User’s access privilege information are the logical OR of the corresponding bits in whichever of the other three bytes apply to the user. For example, if the user is the owner of a directory and is in the directory’s group, then the three low-order bits of the User byte are the logical OR of the corresponding bits in the other three bytes. If, however, the user is not the owner and is not in the directory’s group, the user privilege bits have the same values as the corresponding ones in the Everyone byte.You can use PBHSetDirAccess to set the low-order three bits of all the privileges bytes except for the User’s privileges byte. In the User’s privileges byte, you can set only the blank access privileges bit (bit 28).Not all volumes support blank access privileges. You can call the PBHGetVolParms function to determine whether a particular volume supports blank access privileges.<36pt\>\x12 <8bat\>uRemote Volume MountingTypically, the user mounts remote shared volumes through the Chooser or by opening an alias file. The File Manager in system software version 7.0 and later provides a set of calls that you can use to collect the mounting information from a mounted volume and then use that information to mount the volume again later, without going through the Chooser.Ordinarily, before you can mount a volume programmatically, you must record its mounting information while it’s mounted. Because the size of the mounting information can vary, you first call the PBGetVolMountInfoSize function, which returns the size of the record you’ll need to allocate to hold the mounting information. You then allocate the record and call PBGetVolMountInfo, passing a pointer to the record. When you want to mount the volume later, you can pass the record directly to the PBVolumeMount function.The functions for mounting volumes programmatically are low-level functions designed for specialized applications. Even if your application needs to track and access volumes automatically, it can ordinarily use the Alias Manager, described in the “Alias Manager” chapter of this volume. The Alias Manager can record mounting information and later remount most volumes, even those that do not support the programmatic mounting functions.<36pt\>\x12 <8bat\>uThe programmatic mounting functions can now be used to mount AppleShare volumes. The functions have been designed so that they can eventually be used to mount local Macintosh volumes, such as partitions on devices that support partitioning, and local or remote volumes managed by non-Macintosh file systems.Privilege Information in Foreign File SystemsVirtually every file system has its own privilege model, that is, conventions for controlling access to stored files. A number of non-Macintosh file systems support access from a Macintosh computer by mapping their native privilege models onto the model defined by the AppleTalk Filing Protocol (AFP). Most applications that manipulate files in foreign file systems can rely on the intervening software to translate AFP privileges into whatever is required by the remote system.The correlation is not always simple, however, and some applications require more control over the files stored on the foreign system. The A/UX privilege model, for example, recognizes four kinds of access: read, write, execute, and search. The AFP model recognizes only read and read-and-write access. If a shell program running on the Macintosh Operating System wants to allow the user to set native A/UX privileges on a remote file, it has to communicate with the A/UX file system using the A/UX privilege model.System software version 7.0 provides two new functions, PBGetForeignPrivs and PBSetForeignPrivs, for manipulating privileges in a non-Macintosh file system. The access-control functions were designed for use by shell programs, such as the Finder, that need to use the native privilege model of the foreign file system. Most applications can rely on using shared environment functions, which are recognized by file systems that support the Macintosh privilege model. The new access-control functions do not relieve a foreign file system of the need to map its own privilege model onto the shared environment functions.Like all other low-level File Manager functions, the access-control functions exchange information with your application through parameter blocks. The meanings of some fields depend on what the foreign file system is. These fields are currently defined for A/UX, and you can define them for other file systems. If you are defining a new privilege model, contact Macintosh Developer Technical Support.You can identify the foreign file system through the PBHGetVolParms function. The attributes buffer introduced in system software version 7.0 for the PBHGetVolParms function contains a field for the foreign privilege model, vMForeignPrivID.The value of vMForeignPrivID is unrelated to whether the remote volume supports the AFP access-control functions. You can determine whether the volume supports the AFP access-control functions by checking the bHasAccessCntl bit in the vMAttrib field.<36pt\>\x12 <8bat\>uA value of 0 for vMForeignPrivID signifies an HFS volume that supports no foreign privilege models. The field currently has one other defined value.CONST                    fsUnixPriv = 1;                                    {A/UX privilege model}For an updated list of supported models and their constants and fields, contact Macintosh Developer Technical Support.A volume can support no more than one foreign privilege model.The access-control functions store information in a new parameter block type, foreignPrivParam.The parameter block can store access-control information in one or both ofn    a buffer of any length, whose location and size are stored in the parameter blockn    four long words of data stored in the parameter block itselfThe meanings of the fields in the parameter block depend on the definitions established by the foreign file system. For example, A/UX uses the ioForeignPrivBuffer field to point to a 16-byte privileges data buffer.File ID RoutinesThe File Manager provides a set of three low-level functions for creating, resolving, and deleting file ID references. These functions were developed for use by the Alias Manager, which uses them to track files that have been moved within a volume or renamed. In most cases, your application should track files with the Alias Manager, described in the “Alias Manager” chapter of this volume, not with file IDs.You establish a file ID reference when you need to identify a file using a file number (see “File IDs” later in this chapter). You create a file ID reference with the PBCreateFileIDRef function. Because the File Manager assigns file numbers independently on each volume, file IDs are not unique across volumes.You can resolve a file ID reference by calling the PBResolveFileIDRef function, which determines the name and parent directory ID of the file with a given ID. If you no longer need a file ID, remove its record from the directory by calling the PBDeleteFileIDRef function. Removing a file ID is seldom appropriate, but the function is provided for completeness.Identifying Files, Directories, and VolumesWhenever you want to perform some operation on a file, directory, or volume, you need to identify the target item to the File Manager. Exactly how you specify these items in the file system depends on several factors, including the version of system software currently executing and, if the target item is a file, whether it is open or closed. For example, once you have opened a file, you subsequently identify that file to the File Manager by providing its file reference number, a unique number that is returned to your application when you open the file.In all other cases, you can identify files, directories, and volumes to the File Manager by using a variety of methods. In addition to file reference numbers, the File Manager recognizesn    file system specificationsn    file ID numbersn    directory ID numbersn    volume reference numbersn    working directory reference numbersn    names and full or partial pathnamesThis section describes each of these ways to identify items in the file system. Note however that some of these methods are of historical or theoretical interest only. Working directory reference numbers exist solely to provide compatibility with the now-obsolete Macintosh File System (MFS) and their use is no longer recommended. Similarly, the use of full pathnames to specify volumes, directories, or files is not in general recommended.Whenever possible, you should use file system specifications to identify files and directories because they provide the simplest method of doing this and are recognized by the Finder, the Standard File Package, and other system software components beginning with system software version 7.0. If your application is intended to run in system software versions where the routines that accept file system specification records are not available, you should use the volume reference number, parent directory ID, and name of the item you wish to identify.File System SpecificationsConventions for identifying files, directories, and volumes have evolved as the File Manager has matured. System software version 7.0 introduced a simple, standard form for identifying a file or directory, called a file system specification. You can use a file system specification whenever you must identify a file or directory for the File Manager.A file system specification containsn    the volume reference number of the volume on which the file or directory residesn    the directory ID of the parent directoryn    the name of the file or directoryFor a complete description of the new data structure, the file system specification (FSSpec) record, see “File System Specification Record” later in this chapter.The Standard File Package in system software version 7.0 uses FSSpec records to identify files to be saved or opened. The File Manager provides a new set of high-level routines that accept FSSpec records as input, so that your application can pass the data directly from the Standard File Package to the File Manager. The Alias Manager and the Edition Manager accept file specifications only in the form of FSSpec records.The Finder introduced in version 7.0 uses alias records, which are resolved into FSSpec records, to identify files to be opened or printed. (The description of required Apple events in the Apple Event Manager chapter of the Collaborative Computing volume explains how the Finder passes file information to your application and how your application retrieves it.)Version 7.0 also introduced the FSMakeFSSpec function, which creates an FSSpec record for a file or directory. For a description of FSMakeFSSpec, see “Creating File System Specification Records” later in this chapter.File IDsA file ID is a unique number that the File Manager assigns to a file at the time it is created. The File Manager uses file IDs to distinguish one file from another on the same volume. In fact, a file ID is simply the catalog node ID of a file. As a result, file IDs are functionally analogous to directory IDs (described in the next section), and both kinds of IDs are assigned from the same set of numbers.The File Manager can set up an internal record in the volume’s catalog that records the filename and parent directory ID of the file with a given file ID, enabling you to reference the file by that number. (For more information about the volume’s catalog, see “Catalog Files” later in this chapter.) This internal record in the volume catalog is a file ID reference (or file ID thread record).It is important to distinguish file IDs from file ID references. File IDs exist on all HFS volumes, but file ID references might or might not exist on a particular HFS volume, and even if file ID references do exist on a volume, they might not exist for all the files on that volume. In addition, you can track files using their file IDs only on systems capable of creating and resolving file ID references. See “File ID Routines” for a description of the File Manager functions introduced in system software version 7.0 that allow you to manipulate file IDs.The file ID is a low-level tool and is unique only on one HFS volume. In most cases, your application should track files using the Alias Manager, described in the “Alias Manager” chapter of this volume. The Alias Manager can track files across volumes. It creates a detailed record describing a file that you want to track, and, when you need to resolve the record later, it performs a sophisticated search. The Alias Manager uses file IDs internally.<36pt\>\x12 <8bat\>uA file ID is analogous to a directory ID. A file ID is unique only within a volume. A file ID remains constant even when the file is moved or renamed. When a file is copied or restored from backup, however, the file ID changes. File IDs are unique over time—that is, once an ID has been assigned to a file, that number is not reused even after the file has been deleted.The file ID represents a permanent reference for a file, a reference that a user cannot change. Your application can store a file ID so that it can locate a specific file quickly and automatically, even if the user has moved or renamed it on the same volume.File IDs are intended only as a tool for tracking files, not as a new element in file specification conventions. Neither high-level nor low-level File Manager functions accept file IDs as parameters.Directory IDsA directory ID is a unique number that the File Manager assigns to a directory at the time it is created and which it uses to distinguish one directory from another on the same volume. A directory ID is simply the catalog node ID of a directory. As a result, directory IDs are functionally equivalent to file IDs, and both kinds of IDs are assigned from the same set of numbers.Directory IDs are long integers. Several constants are defined by the File Manager to refer to special directory IDs that exist on every volume.CONST                fsRtParID                =    1;        {directory ID of root directory’s parent}                fsRtDirID                =    2;        {directory ID of volume’s root directory}Every volume’s root directory has a directory ID of 2. In addition, every volume’s root directory has a parent directory ID of 1. There is, however, no such parent directory; the constant fsRtParID is provided solely for use by applications and File Manager routines that need to specify a parent ID when referring to the volume’s root directory. For example, if you call the PBGetCatInfo function when the ioDirID field is set to fsRtDirID, the value fsRtParID will be returned in the ioDrParID field.Volume Reference NumbersA volume reference number is a unique number that is assigned to a volume at the time it is mounted. Unlike the volume name (which the user can change at any time and hence may not be unique), the volume reference number is both unique and unchangeable by the user, so it provides a reliable way to refer to a volume for as long as the volume is mounted. Volume reference numbers are small negative integers. They are valid only until the volume is unmounted. For example, if you place a volume off-line and then bring it back on-line, that volume will have the same volume reference number it was originally assigned. However, if you unmount a volume and then remount it at some later time, its volume reference number might not be the same during both mounts.A volume reference number refers to a volume only as long as the volume is mounted. To create a volume reference that will be valid across subsequent boots, use alias records. See the “Alias Manager” chapter in this volume for details.<36pt\>\x12 <8bat\>uWorking Directory Reference NumbersThe File Manager provides a method of identifying directories known as working directory reference numbers. A working directory is a temporary directory reference that the File Manager uses to specify both a directory and the volume it resides on. Each working directory is assigned a working directory reference number at the time it is created, which can be used in place of a volume reference number in all File Manager routines.Working directories were developed to allow applications written for the now-obsolete Macintosh File System to execute correctly when accessing volumes using the Hierarchical File System. In general, your application should not create working directories and, in the few instances a working directory reference number is returned to your application, it should immediately turn that number into a volume reference number and directory ID.<36pt\>\x12 <8bat\>uThe first file system available on Macintosh computers was the Macintosh File System (MFS), a “flat” file system in which all files are stored in a single directory. The hierarchical organization of folders within folders is an illusion maintained by the system software. As a result, a file can be identified under MFS simply by specifying its name and the volume it is on. Typically, MFS routines require a volume reference number and a filename to specify a file.To improve performance, especially with larger volumes, Apple Computer, Inc., introduced the Hierarchical File System (HFS) on the Macintosh Plus computer and later models. In HFS, a volume can be divided into smaller units known as directories, which can themselves contain files or other directories. This hierarchical relationship of folders corresponds to an actual hierarchical directory structure maintained on disk. (See “Data Organization on Volumes” for the precise details of this hierarchical directory structure.)Each file on an HFS volume is stored in a directory, called the file’s parent directory. To identify a file in HFS, you must specify its volume, its parent directory, and its name. The File Manager assigns each directory a directory ID, and the user or the system software assigns each directory a name. The HFS File Manager routines include an additional parameter to handle the directory specification.To keep existing applications running smoothly, Apple introduced the concept of working directories. A working directory is a combined directory and volume specification. To make a directory into a working directory, the File Manager establishes a working directory control block that contains both the volume and the directory ID of the target directory. The File Manager returns a unique working directory reference number, which can be used instead of the volume reference number in all routines.If your application provides both a directory ID and a working directory reference number, the directory ID is used to specify the directory (overriding the working directory specified by the working directory reference number). The working directory reference number is used to specify the volume (unless a volume name, which overrides all other forms of volume specification, is also provided).<36pt\>\x12 <8bat\>uThe best course of action is to avoid using working directories altogether. In the few cases where system software returns a working directory reference number to your application, the recommended practice is to immediately convert that working directory reference number into its corresponding directory ID and volume reference number (using PBGetWDInfo or its high level equivalent, GetWDInfo).Names and PathnamesVolumes, directories, and files all have names. A volume name is any sequence of 1 to 27 characters, excluding colons (:), that is assigned to a volume. File and directory names consist of any sequence of 1 to 31 characters, excluding colons. You can use uppercase and lowercase letters when naming things, but the File Manager ignores case when comparing names. The File Manager does not however ignore diacritical marks when comparing names.Files and directories that are located in the same directory must all have unique names. However, there is no requirement that volumes have unique names. It is perfectly acceptable for two mounted volumes to have the same name. This is one reason why your application should use volume reference numbers rather than volume names to specify volumes.You can also specify files and directories using pathnames, although this method is discouraged. There are two kinds of pathnames, full and partial. A full pathname is a sequence of directory names, separated by colons, starting from the root directory (or volume) and leading down to the file. A full pathname to the file “bananas,” for instance, might go something like this.MyDisk:things:organic:food:fruits:bananaA partial pathname is a pathname that begins in some directory other than the root directory. A particular directory is specified by volume reference number (in the case of the root directory), working directory reference number, or directory ID, and the pathname begins relative to that directory. If the directory “things” were specified, for instance, the partial pathname to the “banana” file would be:organic:food:fruits:bananaThe use of pathnames, however, is highly discouraged. If the user changes names or moves things around, they are worthless. It’s best to stay with simple file or directory names and specify the directory containing the file or directory by its directory ID.HFS SpecificationsThe simplest way to identify a mounted volume is by giving its volume reference number. The simplest way to identify a file or directory located on a mounted volume is by providing a file system specification. In some cases, however, you might not be able to use file system specifications.For example, when you are using the low-level File Manager routines, you need to specify files and directories using other methods because the low-level routines do not accept file system specifications. You also need to use other methods for identifying files and directories when using the high-level HFS routines that existed prior to the introduction of the FSSpec routines. This section summarizes the conventions used by the File Manager for interpreting the various volume, directory, and file specifications that are available even when file system specifications are not.The File Manager recognizes three kinds of file system objects: files, directories, and volumes. You can identify them using various methods.Object    Method of identificationFile    filenameDirectory    directory name    directory ID    working directory reference number, which also implies a volumeVolume    volume name     volume reference number     working directory reference number, which also implies a directoryIn HFS, you can pass a complete file specification in any of four ways:n    full pathnamen    volume reference number and partial pathnamen    working directory reference number and partial pathnamen    volume reference number, directory ID, and partial pathnameA full pathname consists of the name of the volume, the names of all directories between the root directory and the target, and the name of the target. A full pathname starts with a character other than a colon and contains at least one colon. If the first character is a colon, or if the pathname contains no colons, it is a partial pathname. If a partial pathname starts with the name of a parent directory, the first character in the pathname must be a colon. If a partial pathname contains only the name of the target file or directory, the leading colon is optional.You can identify a volume in the vRefNum parameter by volume reference number or drive number, but volume reference number is preferred. A value of 0 represents the default volume. A volume name in the pathname overrides any other volume specification. Unlike a volume name, a volume reference number is guaranteed to be unique. It changes, however, each time a volume is mounted.A working directory reference number represents both the directory ID and the volume reference number. If you specify any value other than 0 for the dirID parameter, that value overrides the directory ID implied by a working directory reference number in the volume parameter. The volume specification remains valid.Figure 2-2 illustrates the four ways to identify a file in HFS.Identifying a file in HFSUsing the File ManagerYou can use the File Manager to manipulate files, directories, and volumes. The “Introduction to File Management” chapter in this volume shows how to use the File Manager and other system software services to accomplish the most common file-related operations (namely, handling the standard File menu commands). This section shows how to accomplish a variety of other operations on files, directories, and volumes. In particular, this section shows how ton    determine the available features of the File Managern    determine the characteristics of a particular mounted volumen    create file system specification recordsn    manipulate the default volume and directoryn    delete files and file forksn    search a volume for files or directories matching various criterian    construct the full pathname of a filen    determine the amount of free space on a volumen    lock and unlock byte ranges in shared filesAltogether, the code listings given in this section provide a rich source of information about using the many File Manager routines and data structures.Determining the Features of the File ManagerSome of the capabilities provided by the File Manager depend on the version of system software that is running, and some others depend on the characteristics of the target volume. For example, the routines that accept FSSpec records as file or directory specifications were introduced in system software version 7.0 and are unavailable in earlier system software versions unless your software development system provides “glue” that allows you to call those routines when running in earlier system software versions (or unless some system extension provides those routines). Similarly, some volumes support features that other volumes do not; a volume that has local file sharing enabled, for instance, allows you to lock byte ranges in shared files on that volume.Before using any of the File Manager features that are not universally available in all system software versions and on all volumes, you should check for that feature’s availability by calling either the Gestalt function or the PBHGetVolParms function, depending on whether the feature’s presence depends on the system software or the characteristics of the volume.You can use Gestalt to determine whether or not you can call the functions that accept and support FSSpec records. Call Gestalt with the gestaltFSAttr selector to check for File Manager features. The response parameter currently has two relevant bits.CONST    gestaltFullExtFSDispatching                                        =     0;        {exports HFSDispatch traps}    gestaltHasFSSpecCalls                                        =    1;        {supports FSSpec records}Constant descriptionsgestaltFullExtFSDispatching    If set, all of the routines selected through the _HFSDispatch trap are available to external file systems.gestaltHasFSSpecCalls    If set, the operating environment provides the file system specification versions of the basic file manipulation functions, plus the FSMakeFSSpec function.Listing 0-2 in the “Introduction to File Management” chapter illustrates how to use the Gestalt function to determine whether the operating environment supports the FSSpec functions. For a complete description of the Gestalt function, see the “Compatibility Guidelines” chapter in the Overview volume.To test for the availability of the features that depend on the volume, you can call the low-level function PBHGetVolParms. Listing 2-1 illustrates how you can determine whether the PBCatSearch function is available before using it to search a volume’s catalog.Testing for PBCatSearchFUNCTION SupportsCatSearch (vRefNum: Integer): Boolean;VAR                myHPB:                    HParamBlockRec;                volParmsBuf:                    GetVolParmsInfoBuffer;                myErr:                    OSErr;BEGIN                WITH myHPB DO                    BEGIN                        ioCompletion := NIL;                                            {no completion routine}                        ioNamePtr := NIL;                        ioVRefNum := vRefNum;                        ioBuffer := @volParmsBuf;                        ioReqCount := SIZEOF(GetVolParmsInfoBuffer);                    END;                myErr := PBHGetVolParms(@myHPB, FALSE);                IF myErr <> NoErr THEN                    DoError(myErr);                                                {process the error}                IF BTst(volParmsBuf.vMAttrib, bHasCatSearch) THEN                    SupportsCatSearch := TRUE                ELSE                    SupportsCatSearch := FALSE;END;The SupportsCatSearch function simply calls PBHGetVolParms for the volume whose reference number is passed as a parameter to SupportsCatSearch. The PBHGetVolParms function returns information about a volume in a record of type GetVolParmsInfoBuffer. The vMAttrib field of that record contains a number of bits that encode information about the capabilities of the target volume. In particular, the bit bHasCatSearch is set if the specified volume supports the PBCatSearch function.Creating File System Specification RecordsSometimes it is useful for your application to create a file system specification record. For example, your application might be running in an environment where the enhanced Standard File Package routines (which return FSSpec records) are unavailable but the File Manager FSSpec routines are available (perhaps as glue code in your development system). Instead of allocating space for an FSSpec record and filling in the fields of the record yourself, you should always call FSMakeFSSpec (or its low-level equivalent PBMakeFSSpec) to create a file system specification record.Three of the parameters to FSMakeFSSpec represent the volume, parent directory, and file specifications of the target object. You can provide this information in any of the four combinations described earlier in “HFS Specifications.” Table 2-8 details the ways your application can identify the name and location of a file or directory in a call to FSMakeFSSpec.How FSMakeFSSpec interprets file specificationsvRefNum    parID    name    Interpretationignored    ignored    full pathname    Full pathname overrides any other            informationvolume reference    directory ID    partial pathname    Partial pathname starts in the directory whosenumber or drive             directory whose parent is specified in thenumber             dirID parameterworking directory     directory ID    partial pathname    Directory specification in the dirID reference number            parameter overrides the directory implied            by the reference number            Partial pathname starts in the directory            whose parent is specified in dirIDvolume reference    0    partial pathname    Partial pathname starts in the root directorynumber or drive             of the volume in vRefNumnumberworking directory    0    partial pathname    Partial pathname starts in the directoryreference number            specified by the working directory            reference numbervolume reference    directory ID    empty string    The target object is the directory specified number of drive         or NIL    by the directory ID in dirIDnumberworking directory    0    empty string    The target object is the directory specifiedreference number        or NIL     by working directory reference number in             vRefNum volume reference    0    empty string    The target object is the volume specifiednumber or        or NIL    in vRefNumdrive numberThe fourth parameter to FSMakeFSSpec is a pointer to the FSSpec record.Manipulating the Default Volume and DirectoryWhen your application is running, File Manager maintains a default volume and a default directory for it. The default directory is the directory used in File Manager routines whenever you don’t explicitly specify some directory. The default volume is the volume containing the default directory.If you pass 0 as the volume specification with routines that operate on a volume (such as mounting or ejecting), the File Manager assumes that you want to perform the operation on the default volume. Initially, the volume used to start up the application is set as the default volume, but your application can designate any mounted volume as the default volume.With routines that access files or directories, if you don’t specify a directory and you pass a volume specification of 0, the File Manager assumes that the file or directory is located in the default directory. Initially, the default directory is set to the root directory of the default volume, but your application can designate any directory as the default directory.Don’t confuse the default directory and volume maintained by the File Manager with the current directory and volume maintained by the Standard File Package. Although the default volume and current volume are initially the same, they can differ whenever your application resets one of them. See the “Standard File Package” chapter in this volume for more information about the current directory and volume.<36pt\>\x12 <8bat\>uThe provision of a default volume was originally intended as a convenient way for you to limit all File Manager calls to a particular volume. The default directory was introduced along with HFS as an analogue to the default volume. In general, however, it is safest to specify both a volume and a directory explicitly in all File Manager calls. In particular, the introduction of file system specification records has rendered default volumes and directories largely obsolete. As a result, you should avoid relying on them.In some cases, however, you might want to set the default volume or directory explicitly. You can determine the default volume and directory by calling the GetVol or HGetVol functions. You can explicitly set the default directory and volume by calling the SetVol or HSetVol functions. For reasons explained below, however, the use of HSetVol and its low-level equivalent PBHSetVol is discouraged.To set the default volume only, you can call SetVol, passing it the volume reference number of the volume you want to establish as the default volume:myErr := SetVol(NIL, myVRefNum);You can instead specify the volume by name, but because volume names might not be unique, it is best to use the volume reference number.To set both the default directory and the default volume, you could call HSetVol, passing it the appropriate volume reference number and directory ID:myErr := HSetVol(NIL, myVRefNum, myDirID);However, using HSetVol can lead to problems in certain circumstances. When you call HSetVol (or its low-level version PBHSetVol) and pass a working directory reference number in the vRefNum parameter, the File Manager stores the encoded volume reference number and directory ID separately. If you later call GetVol (or  its low-level version PBGetVol), the File Manager returns that volume reference number, not the working directory reference number you passed to HSetVol. The net result is that any code using the results of the GetVol call will be accessing the root directory of the default volume, not the actual default directory.It is important to realize that calling HSetVol is perfectly safe if all the code executing in your application’s partition always calls HGetVol instead of GetVol.  This is because HGetVol returns a working directory reference number whenever the previous call to HSetVol passed one in. The only time that calling HSetVol can be unsafe is when your application is running under a system software version prior to version 7.0. In that case, a desk accessory might be opened in your application’s partition, thereby inheriting your application’s default volume and directory. If that desk accessory calls GetVol instead of HGetVol, it might receive a volume reference number when it expects a working directory reference number, as described in the previous paragraph. To avoid this problem, you can simply use SetVol (or PBSetVol) instead of HSetVol:myErr := SetVol(NIL, myVRefNum);In this case, the myVRefNum parameter should contain a working directory reference number.Deleting Files and File ForksYou can delete a file by calling FSpDelete, HDelete, or PBHDelete. These functions delete both forks of a file by removing the catalog entry for the file and adjusting the volume information block and volume bitmap accordingly. These functions do not actually erase the data in the file’s extents on the disk, so there is a reasonable chance that a good disk utility might be able to salvage a deleted file if the user hasn’t allocated any new file blocks in the meantime.Sometimes you might want to truncate just one fork of a file. Listing 2-2 illustrates how you can truncate a file’s resource fork while preserving the data fork.Deleting a file’s resource forkFUNCTION TruncateRF (myFileSpec: FSSpec): OSErr;VAR                myErr:            OSErr;                {result code}                myFile:            Integer;                {file reference number}BEGIN                myErr := FSpOpenRF(myFileSpec, fsRdWrPerm, myFile);                IF myErr = noErr THEN                    myErr := SetEOF(myFile, 0);                IF myErr = noErr THEN                    myErr := FSClose(myFile);                IF myErr = noErr THEN                    myErr := FlushVol(myFileSpec.vRefNum);                TruncateRF := myErr;END;The function TruncateRF defined in Listing 2-2 opens the file’s resource fork with exclusive read/write permission and sets its logical end-of-file to 0. This effectively releases all the space occupied by the resource fork on the volume. Then TruncateRF closes the file and updates the volume.Searching a CatalogYou can search a volume’s catalog efficiently using the PBCatSearch function. PBCatSearch looks at all entries in all directories on the volume and returns a list of all files or directories that match the criteria you specify. You can ask PBCatSearch to match for names or partial names; file and directory attributes; Finder information; physical and logical file length; creation, modification, and backup dates; and parent directory ID.Like all low-level File Manager functions, PBCatSearch exchanges information with your application through a parameter block. The PBCatSearch function uses the csParam variant of the basic parameter block defined by the HParamBlockRec data type.PBCatSearch accesses file and directory data in a catalog information record (CInfoPBRec). (This record is also used by the PBGetCatInfo function.) You specify the limits of the search criteria for PBCatSearch in two catalog information records, called ioSearchInfo1 and ioSearchInfo2.Some fields in the catalog information records apply only to files, some only to directories, and some to both. Some of the fields that apply to both have different names, depending on whether the target of the record is a file or a directory. PBCatSearch uses only some fields in the catalog information record. Table 2-9 lists the fields used for files, and Table 2-10 lists the fields used for directories.The fields in ioSearchInfo1 and ioSearchInfo2 have different uses:n    The ioNamePtr field in ioSearchInfo1 holds a pointer to the target string; the ioNamePtr field in ioSearchInfo2 must be NIL. (If you’re not searching for the name, the ioNamePtr field in ioSearchInfo1 must also be NIL.)n    The date and length fields in ioSearchInfo1 hold the lowest values in the target range; the date and length fields in ioSearchInfo2 hold the highest values in the target range. PBCatSearch looks for values greater than or equal to the field values in ioSearchInfo1 and less than or equal to the values in ioSearchInfo2.n    The ioFlAttrib and ioFlFndrInfo fields in ioSearchInfo1 hold the target values; the same fields in ioSearchInfo2 hold masks that specify which bits are relevant.Fields in ioSearchInfo1 and ioSearchInfo2 used for a fileOffset    Field    Size    Meaning18    ioNamePtr    Long    Filename30    ioFlAttrib    Byte    File attributes32    ioFlFndrInfo    16 bytes    Finder information (FInfo record,            described in the Finder Interface chapter            of the Toolbox volume)54    ioFlLgLen    Long    Data fork logical length58    ioFlPyLen    Long    Data fork physical length64    ioFlRLgLen    Long    Resource fork logical length68    ioFlRPyLen    Long    Resource fork physical length72    ioFlCrDat    Long    File creation date76    ioFlMDat    Long    File modification date80    ioFlBakDat    Long    File backup date84    ioFlXFndrInfo    16 bytes    Extended Finder information (FXInfo            record, described in the Finder Interface            chapter of the Toolbox volume)100    ioFlParID    Long    File’s parent directory IDFields in ioSearchInfo1 and ioSearchInfo2 used for a directoryOffset    Field    Size    Meaning18    ioNamePtr    Long    Directory name30    ioFlAttrib    Byte    Directory attributes32    ioDrUsrWds    16 bytes    Finder information (DInfo record,            described in the Finder Interface chapter            of the Toolbox volume)52    ioDrNmFls    Word    Number of files in the directory72    ioDrCrDat    Long    Directory creation date76    ioDrMdDat    Long    Directory modification date80    ioDrBakDat    Long    Directory backup date84    ioDrFndrInfo    16 bytes    Extended Finder information (DXInfo            record, described in the Finder Interface            chapter of the Toolbox volume)100    ioDrParID    Long    Directory’s parent directory IDIn a pair of records that describe a file, for example, the variable fields have these meanings:Field    ioSearchInfo1    ioSearchInfo2ioNamePtr    Target string    Reserved (must be NIL)ioFlAttrib    Desired attributes    Mask specifying which attributes are        used in searchioFlFndrInfo    Desired Finder profile    Mask specifying which Finder        information is used in searchioFlLgLen    Smallest desired size    Largest desired sizeioFlPyLen    Smallest desired size    Largest desired sizeioFlRLgLen    Smallest desired size    Largest desired sizeioFlCrDat    Earliest desired date    Latest desired dateioFlMDat    Earliest desired date    Latest desired dateioFlBakDat    Earliest desired date    Latest desired dateioFlXFndrInfo    Desired extended    Mask specifying which extended Finder    Finder profile    information is used in searchPBCatSearch searches only on bits 0 and 4 in the file attributes field (ioFlAttrib):Bit    Meaning0    Set if the file or directory is locked.4    Set if the item is a directory.The additional bits returned in the ioFlAttrib field by the PBGetCatInfo function cannot be used by PBCatSearch.<36pt\>\x12 <8bat\>uTo fully describe the search criteria to PBCatSearch, you pass it a pair of catalog information records that determine the limits of the search and a mask that identifies the relevant fields within the catalog information records. You pass the mask in the ioSearchBits field in the PBCatSearch parameter block. To determine the value of ioSearchBits, add the appropriate constants.CONST                                fsSBPartialName                        =    1;        {substring of name}                fsSBFullName                        =    2;        {full name}                fsSBFlAttrib                        =    4;        {directory flag; software lock flag}                fsSBNegate                        =    16384;    {reverse match status}                {for files only}                fsSBFlFndrInfo                        =    8;        {Finder file info}                fsSBFlLgLen                        =    32;        {data fork logical length}                fsSBFlPyLen                        =    64;        {data fork physical length}                fsSBFlRLgLen                        =    128;        {resource fork logical length}                fsSBFlRPyLen                        =    256;        {resource fork physical length}                fsSBFlCrDat                        =    512;        {file creation date}                fsSBFlMdDat                        =    1024;        {file modification date}                fsSBFlBkDat                        =    2048;        {file backup date}                fsSBFlXFndrInfo                        =    4096;        {more Finder file info}                fsSBFlParID                        =    8192;        {file's parent ID}                {for directories only}                fsSBDrUsrWds                        =    8;        {Finder directory info}                fsSBDrNmFls                        =    16;        {number of files in directory}                fsSBDrCrDat                        =    512;        {directory creation date}                fsSBDrMdDat                        =    1024;        {directory modification date}                fsSBDrBkDat                        =    2048;        {directory backup date}                fsSBDrFndrInfo                        =    4096;        {more Finder directory info}                fsSBDrParID                        =    8192;        {directory's parent ID}Figure 2-3 illustrates how the value in ioSearchBits determines which fields are used in ioSearchInfo1 and ioSearchInfo2.The effect of ioSearchBits on interpretation of ioSearchInfo1 and ioSearchInfo2A catalog entry must meet all of the specified criteria to be placed in the list of matches. After PBCatSearch has completed its scan of each entry, it checks the fsSBNegate bit. If that bit is set, PBCatSearch reverses the entry’s match status (that is, if the entry is a match but the fsSBNegate bit is set, the entry is not put in the list of matches; if it is not a match, it is put in the list).Although the use of PBCatSearch is significantly more efficient than searching the directories recursively, searching a large volume can take long enough to affect user response time. You can break a search into several shorter searches by specifying a maximum length of time in the ioSearchTime field and keeping an index in the ioCatPosition field. PBCatSearch stores its directory-location index in a catalog position record, which is defined by the CatPositionRec data type.TYPE CatPositionRec =                                                                {catalog position record}RECORD                initialize:                LongInt;                                {starting point}                priv:                ARRAY[1..6] OF Integer;                                {private data}END;To start a search at the beginning of the catalog, set the initialize field to 0. When it exits because of a timeout, PBCatSearch updates the record so that it describes the next entry to be searched. When you call PBCatSearch to resume the search after a timeout, pass the entire record that was returned by the last call. PBCatSearch returns a list of the names and parent directories of all files and directories that match the criteria you specify. It places the list in an array pointed to by the FSSpecArrayPtr field.Listing 2-3 illustrates how to use PBCatSearch to find all files (not directories) whose names contain the string “Temp” and that were created within the past two days.Searching a volume with PBCatSearchCONST    kMaxMatches                         =    30;            {find up to 30 matches in one pass}    kOptBufferSize                        =    $4000;            {use a 16K search cache for speed}VAR    myErr:                OSErr;                        {result code of function calls}    myCount:                Integer;                        {loop control variable}    myFName:                Str255;                         {name of string to look for}    myVRefNum:                Integer;                        {volume on which to search}    myDirID:                LongInt;                        {ignored directory ID for HGetVol}    myCurrDate:                LongInt;                        {current date in seconds}    twoDaysAgo:                LongInt;                        {date two days ago in seconds}    myPB:                HParamBlockRec;                        {parameter block for PBCatSearch}    myMatches:                PACKED ARRAY[1..kMaxMatches] OF FSSpec;                                            {put matches here}    mySpec1:                CInfoPBRec;                         {search criteria, part 1}    mySpec2:                CInfoPBRec;                         {search criteria, part 2}    myBuffer:                 PACKED ARRAY[1..kOptBufferSize] OF Char;                                            {search cache}    done:                Boolean;                        {have all matches been found?}PROCEDURE SetupForFirstTime;BEGIN    myErr := HGetVol(NIL, myVRefNum, myDirID);                                                        {search on the default volume}    myFName := 'Temp';                                                     {search for "Temp"}    GetDateTime(myCurrDate);                                                    {get current time in seconds}    twoDaysAgo := myCurrDate - (2 * 24 * 60 * 60);    WITH myPB DO    BEGIN        ioCompletion                    := NIL;                            {no completion routine}        ioNamePtr                    := NIL;                            {no volume name; use vRefNum}        ioVRefNum                    := myVRefNum;                            {volume to search}        ioMatchPtr                     := FSSpecArrayPtr(@myMatches);                                                        {points to results buffer}        ioReqMatchCount                    := kMaxMatches;                            {number of matches}        ioSearchBits                    := fsSBPartialName                            {search on partial name}                                + fsSBFlAttrib                        {search on file attributes}                                + fsSBFlCrDat;                        {search on creation date}        ioSearchInfo1                    := @mySpec1;                            {points to first criteria set}        ioSearchInfo2                    := @mySpec2;                            {points to second criteria set}        ioSearchTime                    := 0;                            {don't time out on searches}        ioCatPosition.initialize := 0;                                                {set hint to 0}        ioOptBuffer                 := @myBuffer;                                 {point to search cache}        ioOptBufSize                 := kOptBufferSize;                                {size of search cache}    END;    WITH mySpec1 DO    BEGIN        ioNamePtr := @myFName;                                                 {point to string to find}        ioFlAttrib := $00;                                                {clear bit 4 to ask for files}        ioFlCrDat := twoDaysAgo;                                                {lower bound of creation date}    END;    WITH mySpec2 DO    BEGIN        ioNamePtr := NIL;                                                {set to NIL}        ioFlAttrib := $10;                                                {set mask for bit 4}        ioFlCrDat := myCurrDate;                                                {upper bound of creation date}    END;END;BEGIN    SetupForFirstTime;                                                    {initialize data records}    REPEAT        myErr := PBCatSearchSync(@myPB);                                                {get some files}        done := (myErr = eofErr);                                                 {eofErr returned when all done}        IF ((myErr = noErr) | done) & (myPB.ioActMatchCount > 0) THEN            FOR myCount := 1 TO myPB.ioActMatchCount DO                Writeln(myMatches[myCount].name);                                                        {report all matches found}    UNTIL done;END.Constructing Full PathnamesAs indicated earlier in the section “Names and Pathnames,” the use of full or partial pathnames is strongly discouraged. Full pathnames are particularly unreliable as a means of identifying files or directories within your application, largely because the user can change the name of any element in the path at virtually any time. In general, you should use a file’s name, parent directory ID, and volume reference number to identify a file you want to open, delete, or otherwise manipulate.If you need to remember the location of a particular file across subsequent system boots, use the Alias Manager to create an alias record describing the file. If the Alias Manager is not available, you can save the file’s name, its parent directory ID, and the name of the volume it’s located on. Although none of these methods is foolproof, they are much more reliable than using full pathnames to identify files.Nonetheless, it is sometimes useful to display a file’s full pathname to the user. For example, a backup utility might display a list of full pathnames of files as it copies them onto the backup medium. Or, a utility might want to show the full pathname of a file in a dialog box when it needs the user’s confirmation to delete the file. No matter how unreliable full pathnames may be from a file specification viewpoint, they are more readily understood by users than volume reference numbers or directory IDs.The technique given below for constructing a full pathname of a file is intended to be used for display purposes only. Applications that depend upon any particular structure of a full pathname are likely to fail on alternate foreign file systems or under future system software versions.<36pt\>\x12 <8bat\>uListing 2-4 shows one way to define a function, GetFullPath, that takes a directory ID and a filename and that returns the full pathname of the file (if any) that corresponds to those parameters. GetFullPath calls the low-level function PBGetCatInfo for the specified directory to determine the name and directory ID of that directory’s parent directory. It then performs the same operation on the parent directory’s parent, continuing until a parent directory with ID fsRtDirID is reached. Under HFS, this is always the ID of a volume’s root directory.Constructing the full pathname of a fileFUNCTION GetFullPath (DirID: LongInt; vRefnum: Integer): Str255;VAR                myPB:                CInfoPBRec;                    {parameter block for PBGetCatInfo}                dirName:                Str255;                    {a directory name}                fullPath:                Str255;                    {full pathname being constructed}                myErr:                OSErr;BEGIN                fullPath := '';                                        {initialize full pathname}                myPB.ioNamePtr := @dirName;                myPB.ioVRefNum := vRefNum;                                        {indicate target volume}                myPB.ioDrParID := DirId;                                        {initialize parent directory ID}                myPB.ioFDirIndex := -1;                                        {get info about a directory}                {get name of each parent directory, up to root directory}                    REPEAT                    myPB.ioDrDirID := myPB.ioDrParID;                    myErr := PBGetCatInfo(@myPB, FALSE);                    IF gHaveAUX THEN                        BEGIN                            IF dirName[1] <> '/' THEN                                dirName := concat(dirName, '/');                        END                    ELSE                        dirName := concat(dirName, ':');                    fullPath := concat(dirName, fullPath);                UNTIL myPB.ioDrDirID = fsRtDirID;                GetFullPath := fullPath;                                        {return full pathname}END;Note that GetFullPath uses either a slash (/) or a colon (:) to separate names in the full path, depending on whether A/UX is running or not. GetFullPath reads the value of the global variable gHaveAUX to determine whether A/UX is running; your application must initialize this variable (preferably by calling the Gestalt function) before it calls GetFullPath.The GetFullPath function defined in Listing 2-4 returns a result of type Str255, which limits the full pathname to 255 characters. An actual full pathname, however, might exceed 255 characters. A volume name can be up to 27 characters, and each directory name can be up to 31 characters. If the average volume and directory name length is about 20 characters, GetFullPath can handle files located only about 12 levels deep. If the average directory name length is closer to the maximum, GetFullPath will provide a full pathname for files located only about 8 levels deep. If necessary, you can overcome this limitation by rewriting GetFullPath to return a handle to the full pathname; the algorithm for ascending the directory hierarchy using PBGetCatInfo will still work, however.Determining the Amount of Free Space on a VolumeYou can determine how much space is free on a particular volume by calling the low-level function PBHGetVInfo. PBHGetVInfo returns in the ioVFrBlk field of the parameter block passed to it the number of free allocation blocks on a volume. It also returns in the ioVAlBlkSiz field the number of bytes in the allocation blocks on that volume. By multiplying those two values together, you can determine how many bytes are free on a particular volume.There is, however, one complication in this process. The ioVFrBlk field of the parameter block is actually an unsigned integer and can contain values from 0 to 65,535. Pascal, however, does not support unsigned integers, so it interprets the values in the ioVFrBlk field as lying in the range –32,768 to 32,767. (Integers are stored as 16-bit quantities where the high-order bit indicates whether the value is true binary or a negated value in its two’s complement positive form.) If, for example, a volume has 40,000 allocation blocks free and your application blindly returned the value in the ioVFrBlk field, it would erroneously report that the volume had –25,536 allocation blocks available.You can circumvent this problem forcing Pascal to interpret the high-order bit as part of the number of free blocks. For example, if you install the value returned in the ioVFrBlk field as the low-order word of a long integer, the high-order bit of that word is no longer the high-order bit of that long integer and hence is not interpreted as a sign indication. The data type TwoIntsMakeALong provides a convenient way to accomplish this:TYPE                    TwoIntsMakeALong     =                            {two integers make a long integer}                RECORD                    CASE Integer OF                        1:    (long: LongInt);                        2:    (ints: ARRAY[0..1] OF Integer);                END;Listing 2-5 ilustrates how to use this technique to determine the amount of free space on a volume (specified by its volume reference number).Determining the amount of free space on a volumeFUNCTION GetVolumeFreeSpace (myVol: Integer): LongInt;VAR                myHPB:            HParamBlockRec;                            {parameter block for PBHGetVInfo}                myErr:            OSErr;                            {result code from PBHGetVInfo}                myRec:            TwoIntsMakeALong;                            {easy way to get an unsigned int}BEGIN                WITH myHPB DO                    BEGIN                        ioCompletion := NIL;                        ioNamePtr := NIL;                        ioVRefNum := myVol;                        ioVolIndex := 0;                    END;                myErr := PBHGetVInfo(@myHPB, FALSE);                IF myErr = noErr THEN                    BEGIN                        myRec.ints[0] := 0;                        myRec.ints[1] := myHPB.ioVFrBlk;                        GetVolumeFreeSpace := myRec.long * myHPB.ioVAlBlkSiz;                    END                ELSE                    GetVolumeFreeSpace := 0;END;If the value passed to GetVolumeFreeSpace is a valid volume reference number, then this function reads the number of free allocation blocks on the volume, installs that number as the low-order word of a long integer, and performs the necessary multiplication to determine how many bytes are free on the volume.You could avoid these complications with unsigned integers by calling PBHGetVInfo as illustrated and then passing the value returned in the ioVDrvInfo field to the high-level function GetVInfo. The technique using the TwoIntsMakeALong data type to convert unsigned integers to long integers is illustrated here because it is useful when reading the fields of many other File Manager data structures from Pascal. For example, the vcbFreeBks field of a volume control block contains an unsigned integer that you can interpret in this way.<36pt\>\x12 <8bat\>uSharing Volumes and DirectoriesThe File Manager includes several functions that allow you to manipulate share points on local volumes that have File Sharing enabled and to obtain a list of user and group names and IDs recognized by the local file server. These functions are especially useful if you need to implement a dialog box that allows the user to designate a volume or directory as a share point or to set the owner, user, and group of a shared folder.The PBShare function makes a volume or directory a share point, hence available on the network. The PBUnshare function undoes the effects of PBShare: it makes an existing share point unavailable on the network. The PBGetUGEntry function lets you create a list of user and group names and IDs on the local server.Before calling any of these functions, you should check to see whether file sharing is enabled on the local machine and, if so, whether the desired local volume is sharable. You can determine whether a particular volume is sharable by using the function VolIsSharable defined in Listing 2-6.Determining whether a volume is sharableFUNCTION VolIsSharable (vRefNum: Integer): Boolean;VAR    myHPB:                    HParamBlockRec;    myInfoBuffer:                    GetVolParmsInfoBuffer;    myErr:                    OSErr;BEGINWITH myHPB DO    BEGIN        ioCompletion := NIL;        ioNamePtr := NIL;        ioVRefNum := vRefNum;        ioBuffer := @myInfoBuffer;        ioReqCount := SizeOf(myInfoBuffer);    END;    myErr := PBHGetVolParms(@myHPB, FALSE);    IF myErr = noErr THEN        IF BTst(myInfoBuffer.vMAttrib, bHasPersonalAccessPrivileges) THEN            VolIsSharable := TRUE        ELSE            VolIsSharable := FALSE    ELSE        VolIsSharable := FALSE;END;The VolIsSharable function inspects the bHasPersonalAccessPrivileges bit returned in the vMAttrib field of the volume information buffer it passed to PBHGetVolParms. If this bit is set, local file sharing is enabled on the specified volume.You can determine whether file sharing is enabled on the local machine using the function SharingIsOn defined in Listing 2-7. Determining whether file sharing is enabledFUNCTION SharingIsOn: Boolean;VAR                myHPB:                HParamBlockRec;                myErr:                OSErr;                volIndex:                Integer;                sharing:                Boolean;BEGIN                sharing := FALSE; {assume File Sharing is off}                volIndex := 1;                REPEAT                    WITH myHPB DO                        BEGIN                            ioCompletion := NIL;                            ioNamePtr := NIL;                            ioVolIndex := volIndex;                        END;                    myErr := PBHGetVInfo(@myHPB, FALSE);                    IF myErr = noErr THEN                        sharing := VolIsSharable(myHPB.ioVRefNum);                    volIndex := volIndex + 1;                UNTIL (myErr <> noErr) OR sharing;                SharingIsOn := sharing;END;SharingIsOn simply calls the VolIsSharable function for each local volume (or until a sharable volume is found). It uses indexed calls to PBHGetVInfo to obtain the volume reference number of each mounted volume.Locking and Unlocking File RangesA file can be opened with shared read/write permission to allow several users to share the data in the file. When your application needs to modify a portion of a file that has been opened with shared read/write permission, it is usually desirable to make that portion of the file unavailable to other users while you are making your changes. You can call the PBLockRange function to lock a range of bytes before modifying the file and then PBUnlockRange to unlock that range after your changes are safely recorded in the file.Locking a range of bytes in a file gives the user exclusive read/write access to that range and makes it inaccessible to other users. Other users can neither write nor read the bytes in that range until you unlock it. If other users attempt to read data from a portion of a file that you have locked, they receive the fLckdErr result code.The functions PBLockRange and PBUnlockRange are effective only on files that are located on volumes or in directories that are shared. In particular, these functions do nothing when used on files that are on local HFS volumes unless the file’s parent directory or some directory in the file’s full pathname is a share point for File Sharing. If you call PBLockRange on a file that is not located on a remote server volume or that is not currently being shared using File Sharing, no range locking occurs. Moreover, PBLockRange does not return a result code indicating that no range-locking has occurred. As a result, you should usually check to see whether range-locking will be effective on a file before attempting to lock the desired range.Listing 2-8 illustrates how you can check to make sure that calling PBLockRange will have the desired effect.Determining whether a file can have ranges lockedFUNCTION RangesCanBeLocked (fRefNum: Integer): Boolean;VAR    myParmBlk:                ParamBlockRec;                                    {basic parameter block}    myErr:                OSErr;BEGIN    WITH myParmBlk DO        BEGIN            ioCompletion := NIL;            ioRefNum := fRefNum;            ioReqCount := 1;                                            {lock a single byte}            ioPosMode := fsFromStart;                                            {at the beginning of the file}            ioPosOffset := 0;        END;    myErr := PBLockRange(@myParmBlk, FALSE);                                                    {lock the byte; ignore result}    myErr := PBLockRange(@myParmBlk, FALSE);                                                    {lock the byte again}    IF myErr = afpRangeOverlap THEN        BEGIN            RangesCanBeLocked := TRUE;                                            {byte was locked the first time}            myErr := PBUnlockRange(@myParmBlk, FALSE);                                                        {unlock the byte}        END    ELSE        RangesCanBeLocked := FALSE;                                                {byte was not locked}END;The function RangesCanBeLocked takes a file reference number of an open file as a parameter; this is the reference number of the file in which you want to lock a range of bytes. The function locks a byte and immediately locks it again. If the second range locking fails with the result code afpRangeOverlap, you know that the first call to PBLockRange was successful.It’s best to check that a file can have byte ranges within it locked each time you want to lock a range. This is because local file sharing can be started or stopped (via the Sharing Setup control panel) while your application is running.<36pt\>\x12 <8bat\>uYou can unlock a locked range of bytes by calling PBUnlockRange. Note that the range to be unlocked must be the exact same range of bytes that was previously locked using PBLockRange. (You can lock and unlock different byte ranges in any order, however.) If for some reason you need to unlock a range of bytes and do not know where the range started or how long the range is, you must close the file to unlock the range. When a file is closed, all locked ranges held by a user are unlocked.If you want to append data to a shared file, you can use PBLockRange to lock the range of bytes from the file’s current logical end-of-file to the last possible addressable byte of the file. Once you have locked that range, you can write data into it. Listing 2-9 shows how to determine the current logical end-of-file and lock the appropriate range.Locking a file range to append data to the fileFUNCTION LockRangeForAppending (fRefNum: Integer; VAR EOF: LongInt): OSErr;VAR    myParmBlk:                ParamBlockRec;                                    {basic parameter block}    myErr:                OSErr;    myEOF:                LongInt;                                    {current EOF of file}BEGIN    myParmBlk.ioCompletion := NIL;    myParmBlk.ioRefNum := fRefNum;    myErr := PBGetEOF(@myParmBlk, FALSE);                                                    {get the current EOF}    IF myErr <> noErr THEN        BEGIN            LockRangeForAppending := myErr;            Exit(LockRangeForAppending);                                            {trouble reading EOF}        END;    myEOF := LongInt(myParmBlk.ioMisc);                                                    {save the current EOF}    WITH myParmBlk DO        BEGIN            ioCompletion := NIL;            ioReqCount := -1;                                            {all addressable bytes}            ioPosMode := fsFromStart;                                            {start range...}            ioPosOffset := myEOF;                                            {...at the current end-of-file}        END;    myErr := PBLockRange(@myParmBlk, FALSE);                                                    {lock the specified range}    EOF := myEOF;                                                     {return current EOF to caller}    LockRangeForAppending := myErr;END;The function LockRangeForAppending first determines the current logical end-of-file. It is important to get this value immediately before attempting to lock a range that depends on it because another user of the shared file might have changed the end-of-file since you last read it. Then LockRangeForAppending locks the range beginning at the current end-of-file and extending for the maximum number of bytes (specified using the special value –1).In effect, this technique locks a range where data does not yet exist. Practically speaking, locking the entire addressable range of a file prevents another user from appending data to the file until you unlock that range. Note that LockRangeForAppending returns the current logical end-of-file to the caller so that the caller can unlock the correct range of bytes when the appending is complete.You can also call PBLockRange to lock a range of bytes when you want to truncate a file. Locking the portion of a file that you want to truncate prevents another user from using that portion during the truncation. Instead of setting the ioPosOffset field to the logical end-of-file (as in Listing 2-9), simply set it to the desired last byte of the truncated file. Similarly, you can lock an entire file fork by setting the ioPosOffset field to 0.Data Organization on VolumesThis section describes how data is organized on HFS volumes. In general, an application that simply manipulates data stored in files does not need to know how that data is organized on a volume or on the physical storage medium containing that volume. The organization described in this section is maintained by the File Manager for its own uses. Some specialized applications and file-system utilities, however, do need to know exactly how file data is stored on a disk.This section is provided primarily for informational purposes. The organization of data on volumes is subject to change, so before you use this information to read or modify the data stored on a volume, be sure to check that the drSigWord field in the master directory block (described in “Master Directory Blocks” later in this chapter) identifies that volume as an HFS volume. <36pt\>\x12 <8bat\>sMuch of the information describing the files and directories on an HFS volume is read into memory when the volume is mounted. (For example, most of the volume’s master directory block is read into memory as a volume control block.) For a description of how that data is organized in memory, see “Data Organization in Memory” later in this chapter. The File Manager uses a number of interrelated structures to manage the organization of data on disk and in memory, so it is easy to lose sight of the simple and elegant scheme that underlies these structures. As you read through this section and the next, you should keep these points in mind:n    The File Manager keeps track of which blocks on a disk are allocated to files and which are not by storing a volume bitmap on disk and in memory. If a bit in the map is set, the corresponding block is allocated to some file; otherwise, the corresponding block is free for allocation.n    The File Manager always allocates logical disk blocks to a file in groups called allocation blocks; an allocation block is simply a group of consecutive logical blocks. The size of a volume’s allocation blocks depends on the capacity of the volume; there can be at most 65,535 allocation blocks on a volume.n    The File Manager keeps track of the directory hierarchy on a volume by maintaining a file called the catalog file; the catalog file lists all the files and directories on a volume, as well as some of the attributes of those files and directories. A catalog file is organized as a B*-tree (or “balanced tree”) to allow quick and efficient searches through a directory hierarchy that is typically quite large.n    The File Manager keeps track of which allocation blocks belong to a file by maintaining a list of the file’s extents; an extent is a contiguous range of allocation blocks allocated to some file, which can be represented by a pair of numbers: the start of the range and the length of the range. The first three extents of most files are stored in the volume’s catalog file. All remaining file extents are stored in the extents overflow file, which is also organized as a B*-tree.n    The first three extents of the catalog file and the extents overflow file are stored in the master directory block (on disk) and the volume control buffer (in memory); a master directory block is always located at a fixed offset from the beginning of a volume, and a volume control block is stored in the VCB queue.Disk and Volume OrganizationA disk is a physical medium capable of storing information. Examples of disks include 3.5-inch floppy disks, SCSI hard disks and CD-ROM discs, and even RAM disks. An SCSI disk may be divided into one or more partitions. A partition is simply part of a disk that has been allocated to a particular operating system, file system, or device driver. For example, a single SCSI disk can be partitioned into both Macintosh partitions and A/UX partitions. The Macintosh partitions are typically used to hold Macintosh volumes. An A/UX partition can contain an A/UX file system, but it can also be used as a paging area for virtual memory or as a storage area for autorecovery files.The information describing the division of an SCSI disk into partitions is contained in the disk’s partition map, which is always located in the first physical block (512 bytes) on a disk. The partition map specifies the first and last physical blocks in each partition, as well as additional information about the partition (such as its type). The exact structure of a partition map is described in the SCSI Manager chapter in the Devices volume. Often the first partition on a SCSI disk, following the partition map, is the driver partition that contains the actual device driver used to communicate with the disk. (There is, however, no requirement that the driver partition be the first partition on a disk.) Figure 2-4 illustrates a typical organization of partitions on a disk.Organization of partitions on a diskA partition can contain at most one volume. A volume is a single disk partition that contains both file data and the file and directory information necessary to maintain the appropriate data organization or file system. For example, a volume can contain a Macintosh, ProDOS, MS-DOS, or A/UX file system structure. Notice in Figure 2-4 that a Macintosh volume occupies only part of the entire physical disk, and that there can be multiple partitions (both Macintosh volumes or other types of partitions) on a given disk.The disk organization illustrated in Figure 2-4 does not apply to Macintosh 3.5-inch floppy disks. Each floppy disk is one volume, so there is no need for a disk partition map. Also, there is no device driver partition on a floppy disk.<36pt\>\x12 <8bat\>uThe remainder of this section describes only HFS volumes, that is, Macintosh file systems organized using the hierarchical file system (HFS) implemented on the Macintosh Plus and later models.Each HFS volume begins with two boot blocks. The boot blocks on the startup volume are read at system startup time and contain booting instructions and other important information such as the name of the System file and the Finder. Following the boot blocks are two additional structures, the master directory block and the volume bitmap. The master directory block contains information about the volume, such as the date and time of the volume’s creation and the number of files on the volume. The volume bitmap contains a record of which blocks in the volume are currently in use.The largest portion of a volume consists of four types of information or areas:n    applications and data filesn    the catalog filen    the extents overflow filen    unused spaceThe general structure of an HFS volume is illustrated in Figure 2-5. Organization of a volumeAll the areas on a volume are of fixed size and location, except for the catalog file and the extents overflow file. These two files can appear anywhere between the volume bitmap and the alternate MDB. They can appear in any order and are not necessarily contiguous.The information on all block-formatted volumes is organized in logical blocks and allocation blocks. Logical blocks contain a number of bytes of standard information (512 bytes on Macintosh-initialized volumes). Allocation blocks are composed of any integral number of logical blocks, and are simply a means of grouping logical blocks together in more convenient parcels. The allocation block size is a volume parameter whose value is set when the volume is initialized; it cannot be changed unless the volume is reinitialized.To promote file contiguity and avoid fragmentation, space is allocated to files in groups of allocation blocks, or clumps. The clump size is always a multiple of the allocation block size, and it’s the minimum number of bytes to allocate each time the Allocate function is called or the end-of-file is reached during a write operation. The clump size is specified in the catalog information for a file; you can determine  the clump size using the PBGetCatInfo function.The rest of this section describes in detail the structure of the boot blocks, the master directory block, and the catalog and extents overflow files. It also describes the general structure of a B*-tree, because the catalog and extents overflow files are both organized as B*-trees.Boot BlocksThe first two logical blocks on every Macintosh volume are boot blocks. These blocks contain system startup information: instructions and information necessary to start up (or “boot”) a Macintosh computer. This information consists of certain configurable system parameters (such as the capacity of the event queue, the number of open files allowed, and so forth) and is contained in a boot block header. The system startup information also includes actual machine-language instructions that could be used to load and execute the System file. Usually these instructions follow immediately after the boot block header. Generally, however, the boot code stored on disk is ignored in favor of boot code stored in a resource in the System file.For a description of the boot process and of routines that allow you to configure the system startup process, see the “Start Manager” chapter in this volume. The boot block header has a structure that can be described by the Pascal BootBlkHdr data type.The format of the boot block header is subject to change. If your application relies on the information presented here, it should check the boot block header version number and react gracefully if that number is greater than that documented here. <36pt\>\x12 <8bat\>sNote that there are two boot block header formats. The current format includes two fields at the end that are not contained in the older format. These fields allow the Operating System to size the System heap relative to the amount of available physical RAM. A boot block header that conforms to the older format sizes the System heap absolutely, using values specified in the header itself. You can determine whether a boot block header uses the current or the older format by inspecting a bit in the high-order byte of the bbVersion field, as explained in its field description.TYPE BootBlkHdr                                    =                {boot block header}RECORD                bbID:                        Integer;            {boot blocks signature}                bbEntry:                        LongInt;            {entry point to boot code}                bbVersion:                        Integer;            {boot blocks version number}                bbPageFlags:                        Integer;            {used internally}                bbSysName:                        Str15;            {System filename}                bbShellName:                        Str15;            {Finder filename}                bbDbg1Name:                        Str15;            {debugger filename}                bbDbg2Name:                        Str15;            {debugger filename}                bbScreenName:                        Str15;            {name of startup screen}                bbHelloName:                        Str15;            {name of startup program}                bbScrapName:                        Str15;            {name of system scrap file}                bbCntFCBs:                        Integer;            {number of FCBs to allocate}                bbCntEvts:                        Integer;            {number of event queue elements}                bb128KSHeap:                        LongInt;            {system heap size on 128K Mac}                bb256KSHeap:                        LongInt;            {used internally}                bbSysHeapSize:                        LongInt;            {system heap size on all machines}                filler:                        Integer;            {unused}                bbSysHeapExtra:                        LongInt;            {additional system heap space}                bbSysHeapFract:                        LongInt;            {fraction of RAM for system heap}END;bbID    A signature word. For Macintosh volumes, this field always contains the value $4C4B.bbEntry    The entry point to the boot code stored in the boot blocks. This field contains machine-language instructions that translate to BRA.S *+$90 (or BRA.S *+$88, if the older block header format is used), which jumps to the main boot code following the boot block header. This field is ignored, however, if bit 6 is clear in the high-order byte of the bbVersion field or if the low-order byte in that field contains $D.bbVersion    A flag byte and boot block version number. The high-order byte of this field is a flag byte whose bits have the following meanings:    Bit    Meaning    0–4    Reserved; must be 0    5    Set if relative system heap sizing is to be used    6    Set if the boot code in boot blocks is to be executed    7    Set if new boot block header format is used    If bit 7 is clear, then bits 5 and 6 are ignored and the version number is found in the low-order byte of this field. If that byte contains a value that is less than $15, the Operating System ignores any values in the bb128KSHeap and bbSysHeapSize fields and configures the System heap to the default value contained in the bbSysHeapSize field. If that byte contains a value that is greater than or equal to $15, the Operating System sets the System heap to the value in bbSysHeapSize. In addition, the Operating System executes the boot code in the bbEntry field only if the low-order byte contains $D.    If bit 7 is set, the Operating System inspects bit 6 to determine whether to execute the boot code contained in the bbEntry field and bit 5 to determine whether to use relative System heap sizing. If bit 5 is clear,  the Operating System sets the System heap to the value in bbSysHeapSize. If bit 5 is set, the System heap is extended by the value in bbSysHeapExtra plus the fraction of available RAM specified in bbSysHeapFract.bbPageFlags    Used internally.bbSysName    The name of the System file.bbShellName    The name of the shell file. Usually, the system shell is the Finder.bbDbg1Name    The name of the first debugger installed during the boot process. Typically this is Macsbug.bbDbg2Name    The name of the second debugger installed during the boot process. Typically this is Disassembler.bbScreenName    The name of the file containing the startup screen. Usually this is StartUpScreen.bbHelloName    The name of the startup program. Usually this is Finder.bbScrapName    The name of the system scrap file. Usually this is Clipboard.bbCntFCBs    The number of file control blocks (FCBs) to put in the FCB buffer. In system software version 7.0 and later, this field specifies only the initial number of FCBs in the FCB buffer, because the Operating System can usually resize the FCB buffer if necessary. See “File Control Blocks” later in this chapter for details on the FCB buffer.bbCntEvts    The number of event queue elements to allocate. This number determines the maximum number of events that can be stored by the Event Manager at any one time. Usually this field contains the value 20.bb128KSHeap    The size of the System heap on a Macintosh computer having 128 KB of RAM.bb256KSHeap    Unused.bbSysHeapSize    The size of the System heap on a Macintosh computer having 512 KB or more of RAM. This field might be ignored, as explained in the description of the bbVersion field.filler    Unused.bbSysHeapExtra    The minimum amount of additional System heap space required. If bit 5 of the high-order word of the bbVersion field is set, this value is added to the bbSysHeapSize.bbSysHeapFract    The fraction of RAM available to be used for the System heap. If bit 5 of the high-order word of the bbVersion field is set, this fraction of available RAM is added to the bbSysHeapSize.Master Directory BlocksA master directory block (MDB)—also sometimes known as a volume information block (VIB)—contains information about the rest of the volume. This information is written into the MDB when the volume is initialized. Thereafter, whenever the volume is mounted, the File Manager reads the information in the MDB and copies some of that information into a volume control block (VCB). A VCB is a private data structure maintained in memory by the File Manager (in the VCB queue). The structure of a VCB is described in “Volume Control Blocks” later in this chapter.Note in Figure 2-5 that a copy of the MDB is located in the next-to-last block in the volume. This copy is updated only when the extents overflow file or the catalog file grow larger. This alternate MBD is intended for use solely by disk utilities.The MDB data type defines a master directory block record.TYPE MDB                        =                {master directory block}RECORD    drSigWord:                    Integer;                {volume signature}    drCrDate:                    LongInt;                {date and time of volume creation}    drLsMod:                    LongInt;                {date and time of last modification}    drAtrb:                    Integer;                {volume attributes}    drNmFls:                    Integer;                {number of files in root directory}    drVBMSt:                    Integer;                {first block of volume bitmap}    drAllocPtr:                    Integer;                {start of next allocation search}    drNmAlBlks:                    Integer;                {number of allocation blocks in volume}    drAlBlkSiz:                    LongInt;                {size (in bytes) of allocation blocks}    drClpSiz:                    LongInt;                {default clump size}    drAlBlSt:                    Integer;                {first allocation block in volume}        drNxtCNID:                    LongInt;                {next unused catalog node ID}    drFreeBks:                    Integer;                {number of unused allocation blocks}    drVN:                    String[27];                {volume name}    drVolBkUp:                    LongInt;                {date and time of last backup}    drVSeqNum:                    Integer;                {volume backup sequence number}    drWrCnt:                    LongInt;                {volume write count}    drXTClpSiz:                    LongInt;                {clump size for extents overflow file}    drCTClpSiz:                    LongInt;                {clump size for catalog file}    drNmRtDirs:                    Integer;                {number of directories in root directory}    drFilCnt:                    LongInt;                {number of files in volume}    drDirCnt:                    LongInt;                {number of directories in volume}    drFndrInfo:                    ARRAY[1..8} OF LongInt;                                        {information used by the Finder}    drVCSize:                    Integer;                {size (in blocks) of volume cache}    drVBMSize:                    Integer;                {size (in blocks) of volume bitmap cache}    drCtlCSize:                    Integer;                {size (in blocks) of common volume cache}    drXTFlSize:                    LongInt;                {size of extents overflow file}    drXTExtRec:                    ExtDataRec;                {extent record for extents overflow file}    drCTFlSize:                    LongInt;                {size of catalog file}    drCTExtRec:                    ExtDataRec;                {extent record for catalog file}END;drSigWord    The volume signature. For HFS volumes, this field contains $4244; for the obsolete flat MFS volumes, this field contains $D2D7.drCrDate    The date and time of volume creation (initialization).drLsMod    The date and time the volume was last modified. This is not necessarily when the volume was last flushed.drAtrb    Volume attributes. Currently the following bits are defined:    Bit    Meaning    7    Set if the volume is locked by hardware    8    Set if the volume was successfully unmounted    9    Set if the volume has had its bad block spared    15    Set if the volume is locked by softwaredrNmFls    The number of files in the root directory.drVBMSt    The first block of the volume bitmap. This field always contains 3 in the current implementation.drAllocPtr    The number of the allocation block at which the next allocation search will begin. Used internally.drNmAlBlks    The number of allocation blocks in the volume. Note that the value in this field is an integer, so a volume can contain at most 65,535 allocation blocks.drAlBlkSiz    The allocation block size (in bytes). This value must always be a multiple of 512 bytes.drClpSiz    The default clump size.drAlBlSt    The location of the first allocation block in the volume.drNxtCNID    The next unused catalog node ID (directory ID or file ID).drFreeBks    The number of unused allocation blocks on the volume.drVN    The volume name. This field consists of a length byte followed by 27 bytes. Note that the volume name can occupy at most 27 characters; this is an exception to the normal file and directory name limit of 31 characters.drVolBkUp    The date and time of the last volume backup.drVSeqNum    Volume backup sequence number. Used internally.drWrCnt    The volume write count (that is, the number of times the volume has been written to).drXTClpSiz    The clump size for the extents overflow file.drCTClpSiz    The clump size for the catalog file.drNmRtDirs    The number of directories in the root directory.drFilCnt    The number of files on the volume.drDirCnt    The number of directories on the volume.drFndrInfo    Information used by the Finder. See the Finder Interface chapter in the Macintosh Toolbox volume for details on Finder information.drVCSize    The size (in allocation blocks) of the volume cache. Used internally.drVBMCSiz    The size (in allocation blocks) of the volume bitmap cache. Used internally.drCtlCSiz    The size (in allocation blocks) of the common volume cache. Used internally.drXTFlSize    The size (in allocation blocks) of the extents overflow file.drXExtRec    First extent record for the extents overflow file. An extent record is an array of three extents. See “Extents Overflow Files” on page 2-69 for a description of extents and extent records.drCTFlSize    The size (in allocation blocks) of the catalog file.drCExtRec    First extent record for the catalog file.The values in the drNmAlBlks and drFreeBks fields should be interpreted as unsigned integers (that is, they can range from 0 to 65,535, not from –32,768 to 32,767). Pascal does not support unsigned data types, so you need to use the technique illustrated in “Determining the Amount of Free Space on a Volume” to correctly read the values in these fields.<36pt\>\x12 <8bat\>uVolume BitmapsThe File Manager uses the volume bitmap to keep track of whether each block in the volume is currently allocated to some file or not. The bitmap contains one bit for each allocation block in the volume. If a bit is set, the corresponding allocation block is currently in use by some file. If a bit is clear, the corresponding allocation block is not currently in use by any file and is available for allocation. The volume bitmap indicates which blocks on a volume are currently in use, but it does not indicate which files occupy which blocks. The File Manager maintains file-mapping information in two locations: in each file’s catalog entry and in the extents overflow file.<36pt\>\x12 <8bat\>uThe size of the volume bitmap depends on the number of allocation blocks in the volume, which in turn depends both on the number of physical blocks in the volume and on the size of the volume’s allocation blocks (the number of physical blocks per allocation block). For example, a floppy disk that can hold 800 KB of data and has an allocation block size of one physical block has a volume bitmap size of 1600 bits (200 bytes). A volume containing 32 MB of data and having an allocation block size of one physical block has a volume bitmap size of 65,536 bits (8,192 bytes). However, the size of the volume bitmap is rounded up, if necessary, so that the volume bitmap occupies an integral number of physical blocks.Because the drNmAlBlks field in the MDB occupies only 2 bytes, the File Manager can address at most 65,535 allocation blocks, so the volume bitmap is never larger than 8,192 bytes (or 16 physical blocks). For volumes containing more than 32 MB of space, the allocation block size must be increased. For example, a volume containing 40 MB of space must have an allocation block size that is at least 2 physical blocks; a volume containing 80 MB of space must have an allocation block size that is at least 3 physical blocks; and so forth. B*-TreesThe File Manager maintains information about a volume’s directory hierarchy and file block mapping in two files that are organized as B*-trees to allow quick and efficient retrieval of that information. In a B*-tree, all the information that needs to be stored is intelligently classified and sorted into objects called nodes. Figure 2-6 illustrates the general structure of a B*-tree file.The structure of a B*-tree fileNote that each B*-tree file used by the File Manager makes use of the data fork only; the resource fork of a B*-tree file is unused. The length of a B*-tree file varies, depending on the number of nodes it contains. A node in turn contains records, which can be used for a variety of purposes. Some records contain the actual data that is to be retrieved and possibly updated; these records occupy nodes called leaf nodes. Other records contain information about the structure of the B*-tree itself that allows the File Manager to find the information it needs quickly. There are three types of these “bookkeeping” nodes: header nodes, index nodes, and map nodes.NodesA B*-tree file consists entirely of objects called nodes, each of which is 512 bytes long. Figure 2-7 illustrates the structure of a node.The structure of a nodeEach node has the same general structure and consists of three main parts: a node descriptor that starts at the beginning of the node, a group of record offsets that starts at the end of the node, and a group of records. The node descriptor contains information about the node, as well as forward and backward links to other nodes. The structure of a node descriptor can be illustrated using the NodeDescriptor data type.TYPE NodeDescriptor                                        =                {node descriptor}RECORD                ndFLink:                    LongInt;                    {forward link}                ndBLink:                    LongInt;                    {backward link}                ndType:                    SignedByte;                    {node type}                ndNHeight:                    SignedByte;                    {node level}                ndNRecs:                    Integer;                    {number of records in node}                ndResv2:                    Integer;                    {reserved}END;ndFLink    A link to the next node of this type. If this node is the last node, this field contains NIL.ndBLink    A link to the previous node of this type. If this node is the first node, this field contains NIL.ndType    The type of this node. Currently four types of nodes are recognized, defined by the constants listed in this section.ndNHeight    The level or “depth” of this node in the B*-tree hierarchy. The top level node (a header node, described below) always has a level of 0; all other nodes have a level that is one greater than their parent node. Currently, the maximum depth of a node is 8.ndNRecs    The number of records contained in this node.ndResv2    Reserved. This field should always be 0.A node descriptor is always $0E bytes in length, so the records contained in the node always begin at offset $0E from the beginning of the node. The size of a record can vary, depending on its type and on the amount of information it contains; as a result, the File Manager accesses a record by storing the offset from the beginning of the node to that record in the list of offsets found at the end of the node. Each offset occupies a word and (as you might have guessed) the last word in a node always contains the value $0E, pointing to the first record in the node. The offsets to subsequent records are stored in order starting from the end of the node, as illustrated in Figure 2-7.Note that there is always one more offset than the number of records contained in a node; this is an offset to the beginning of any unused space in the node. If there is no free space in the node, then that offset contains its own byte offset within the node.The ndType field of the node descriptor indicates the type of a node. In essence, the type of a node indicates what kinds of records it contains, and hence what its function in the B*-tree hierarchy is. The File Manager maintains four kinds of nodes in a B*-tree, indicated by constants:CONST                                                     {node types}                ndIndxNode                    =    $00;            {index node}                ndHdrNode                    =    $01;            {header node}                ndMapNode                    =    $02;            {map node}                ndLeafNode                    =    $FF;            {leaf node}These node types are described in the four sections that follow the next section.Node RecordsA record in a B*-tree node contains either data or a pointer to some other node in the tree. Figure 2-8 shows the general structure of a record in a leaf or index node.Structure of a B*-tree node recordThe three records in a B*-tree header node do not have the structure depicted in Figure 2-8. They consist solely of data, as described in the next section, “Header Nodes.” Similarly, the single record in a map node consists solely of data; see “Map Nodes”later in this chapter for details.<36pt\>\x12 <8bat\>uEach record contains a search key, which the File Manager uses to search through the B*-tree to locate the information it needs. The key can contain any information at all that is deemed useful in finding the data contained in the leaf nodes. In a catalog file, which maintains information about the hierarchy of files and directories on a volume, the search key is a combination of the file or directory name and the parent directory ID of that file or directory. In an extents overflow file, which maintains information about the extra extents belonging to a file, the search key is a combination of that file’s type, its file ID, and the index of the first allocation block in the extent.In a B*-tree, the records in each node are always grouped so that their keys are in ascending order. Moreover, the nodes on any given level are linked (through the ndFLink and ndBLink fields of their node descriptors) in such a way as to preserve the ascending order of record keys thoughout that level. This is the essential ordering principal that allows the File Manager to search quickly through a tree. To illustrate this ordering scheme, Figure 2-9 shows a sample B*-tree containing hypothetical search keys (in this case, the keys are simply integers).A sample B*-treeWhen the File Manager needs to find a data record, it begins searching at the root node (which is an index node, unless the tree has only one level), moving from one record to the next until it finds the record with the highest key that is less than or equal to the search key. The pointer of that record leads to another node, one level down in the tree. This process continues until the File Manager reaches a leaf node; then the records of that leaf node are examined until the desired key is found. At that point, the desired data has also been found.There is of course no guarantee that a record having the desired key will always be found in a search through a B*-tree. In this case, the search stops when a key larger than the search key is reached. (This is most likely to happen in a search through the catalog file.)Header NodesThe first node (that is, node 0) in every B*-tree file is a header node, which contains essential information about the entire B*-tree file. The File Manager stores the location of the header node of the catalog file in the first 2 bytes of the drCTExtRec field of the MDB; the value in those two bytes indicates the allocation block number on which the catalog file (and hence the header node) begins. Similarly, the File Manager stores the location of the header node of the extents overflow file in the first 2 bytes of the drXTExtRec field of the MDB.When a volume is mounted, the File Manager reads the header node and copies some of the information it contains into a B*-tree control block in memory. See “B*-Tree Control Blocks” later in this chapter for a description of this control block.<36pt\>\x12 <8bat\>uA header node contains three records, the second of which occupies 128 bytes and is reserved for use by the File Manager. The other two records are called the B*-tree header record and the B*-tree map record; they occupy the first and third record positions, respectively. Hence, a header node has the structure illustrated in Figure 2-10.Header node structureThe three records contained in the header node do not contain keys.<36pt\>\x12 <8bat\>uThe map record is a bitmap that indicates which nodes in the B*-tree file are used and which are not. The bits are interpreted in exactly the same way as the bits in the volume bitmap: if a bit in the map record is set, then the corresponding node in the B*-tree file is being used. This bitmap occupies 256 bytes and can therefore encode information about at most 2048 nodes. If more nodes are needed to contain all the data that is to be stored in the B*-tree, the File Manager uses a map node to store additional mapping information. See the next section, “Map Nodes”, for a description of the structure of a map node.The B*-tree header record contains information about the beginning of the tree, as well as the size of the tree. The structure of a B*-tree header record can be depicted using the BTHdrRec data type.TYPE BTHdrRec                                    =                {B*-tree header}RECORD                bthDepth:                    Integer;                {current depth of tree}                bthRoot:                    LongInt;                {number of root node}                bthNRecs:                    LongInt;                {number of leaf records in tree}                bthFNode:                    LongInt;                {number of first leaf node}                bthLNode:                    LongInt;                {number of last leaf node}                bthNodeSize:                    Integer;                {size of a node}                bthKeyLen:                    Integer;                {maximum length of a key}                bthNNodes:                    LongInt;                {total number of nodes in tree}                bthFree:                    LongInt;                {number of free nodes}                bthResv:                    ARRAY[1..76] OF SignedByte;                                        {reserved}END;bthDepth    The current depth of the B*-tree.bthRoot    The node number of the root node. The root node is the start of the B*-tree structure; usually the root node is first index node, but it might be a leaf node if there are no index nodes.bthNRecs    The number of data records (records contained in leaf nodes).bthFNode    The node number of the first leaf node.bthLNode    The node number of the last leaf node.bthNodeSize    The size (in bytes) of a node. Currently, this is always 512.bthKeyLen    The maximum length of the key records in each node.bthNNodes    The total number of nodes in the B*-tree.bthFree    The total number of free nodes in the B*-tree.bthResv    Reserved.Map NodesAs indicated in the previous section, the File Manager maintains a bitmap of the tree nodes in the map record of the B*-tree header node. If a B*-tree file contains more than 2048 nodes (enough for about 8,000 files), the File Manager uses a map node to store additional node-mapping information. It stores the node number of the new map node in the ndFLink field of the node descriptor of the header node.A map node consists of a node descriptor and a single map record. The map record is a continuation of the map record contained in the header node and occupies 494 bytes (512 bytes in the node, less 14 bytes for the node descriptor and 2 bytes for each of the two record offsets at the end of the node). A map node can therefore contain mapping information for an additional 3952 nodes.If a B*-tree contains more than 6000 nodes (that is, 2048 + 3952, enough for about 25,000 files), the File Manager uses a second map node, the node number of which is stored in the ndFLink field of the node descriptor of the first map node. If more map nodes are required, each additional map node is similarly linked to the previous one.Index NodesAn index node is a node that contains records that point to other nodes in the B*-tree hierarchy (called pointer records). The File Manager uses index nodes to navigate the tree structure quickly when it wants to find some data (which is always stored in leaf nodes). Index nodes speed a tree search by dividing the tree into smaller pieces, as illustrated in Figure 2-9.What are contents of index node? what comes after key record? Node number?The immediate descendants of an index node are called the children of the index node. An index node can have from 1 to 15 children, depending on the size of the pointer records that the index node contains. Typically the File Manager selects one of the node’s children and continues the search at that node; the File Manager may stop the search, however, if the index node does not contain a pointer record with the appropriate key.The first index node in a B*-tree is called the root node. Recall that the B*-tree header node contains the node number of the root node in the bthRoot field of the header record. Leaf NodesThe bottom level of a B*-tree structure is occupied exclusively by leaf nodes, which are nodes that contain data records (not pointer records). The exact structure of the leaf node data records depends on the type of B*-tree under consideration. In an extents overflow file, the leaf node data records consist of a key and an extent record. In a catalog file, the leaf node data records can be any one of four kinds of records, described in the next section. Catalog FilesThe File Manager uses a file called the catalog file to maintain information about the hierarchy of files and directories on a volume. A catalog file is organized as a B*-tree file and hence consists of a header node, index nodes, leaf nodes, and (if necessary) map nodes. The allocation block number of the first file extent of the catalog file (and hence of the file’s header node) in stored in the MDB; when the volume is mounted, that information is copied into that volume’s volume control block. From the header node, the File Manager can obtain the node number of the catalog file’s root node; from the root node, the File Manager can find the entire catalog file.Each node of the catalog file is assigned a unique catalog node ID (CNID). For directories, the CNID is the directory ID; for files, it’s the file ID. For any given file or directory, the parent ID is the CNID of the parent directory. The first 16 CNIDs are reserved for use by Apple, and include the following standard assignments:CNID    Assignment1    Parent ID of the root directory2    Directory ID of the root directory3    File number of the extents file4    File number of the catalog file5    File number of the bad allocation block fileYou need to know only two things about a catalog file in addition to the information given earlier in this chapter in “B*-Trees”:n    the format of the catalog key used in index and leaf nodesn    the format of the leaf node data recordsThese formats are described in the following two sections.Catalog File KeysThe key that the File Manager uses to navigate the catalog file is simple: for a given file or directory, the key consists principally of the name of that file or directory and its parent directory ID. With the exception of a volume reference number (which is not needed here), this mirrors the standard way to specify a file or directory when using the high-level HFS routines. In particular, the catalog file key can be described using a record of the CatKeyRec data type.TYPE CatKeyRec                                    =                    {catalog key record}RECORD                ckrKeyLen:                    SignedByte;                    {key length}                ckrResrv1:                    SignedByte;                    {reserved}                ckrParID:                    LongInt;                    {parent directory ID}                ckrCName:                    Str31;                    {catalog node name}END;ckrKeyLen    The length (in bytes) of the rest of the key. The value in this field does not include the byte occupied by the field itself. If this field contains 0, the key indicates a deleted record.ckrResrv1    Reserved.ckrParID    The catalog node ID of the parent directory.ckrCName    The name of the file or directory whose catalog entry is to be found. This field is padded with null characters if necessary to have the next record data or pointer begin on a word boundary.You should pay special attention to the fact that the catalog key differs slightly depending on whether it occurs in a record in an index node or a leaf node. If the key occurs in a pointer record (hence in an index node), the ckrCName field always occupies a full 32 bytes and the ckrKeyLen field always contains the value $25.If, however, the catalog file key occurs in a data record (hence in a leaf node), then the ckrCName field varies in length; it occupies only the number of bytes required to hold the file or directory name, suitably padded so that the data following it begins on a word boundary. In that case, the ckrKeyLen field varies as well, and may contain values from $7 to $25.Catalog File Data RecordsA catalog file leaf node can contain four different types of records.n    Directory records. A directory record contains information about a single directory.n    File records. A file record contains information about a single file.n    Directory thread records. A directory thread record provides a link between a directory and its parent directory. It allows the File Manager to find the name and directory ID of the parent of a given directory.n    File thread records. A file thread record provides a link between a file and its parent directory. It allows the File Manager to find the name and directory ID of the parent of a given file.Each record is defined by a variant of the CatDataType data type.TYPE CatDataType                                    =    (cdrDirRec, cdrFilRec, cdrThdRec,                                         cdrFThdRec);TYPE CatDataRec                                    =                {catalog data records}RECORD                cdrType:                    SignedByte;                {record type}                cdrResrv2:                    SignedByte;                {reserved}CASE CatDataType OFcdrDirRec:                                                    {directory record}              (dirFlags:                        Integer;                {directory flags}                dirVal:                    Integer;                {directory valence}                dirDirID:                    LongInt;                {directory ID}                dirCrDat:                    LongInt;                {date and time of creation}                dirMdDat:                    LongInt;                {date and time of last modification}                dirBkDat:                    LongInt;                {date and time of last backup}                dirUsrInfo:                    DInfo;                {Finder information}                dirFndrInfo:                    DXInfo;                {additional Finder information}                dirResrv:                    ARRAY[1..4] OF LongInt);                                                    {reserved}cdrFilRec:                                                    {file record}              (filFlags:                        SignedByte;                {file flags}                filTyp:                    SignedByte;                {file type}                filUsrWds:                    FInfo;                {Finder information}                filFlNum:                    LongInt;                {file ID}                filStBlk:                    Integer;                {first alloc. blk. of data fork}                filLgLen:                    LongInt;                {logical EOF of data fork}                filPyLen:                    LongInt;                {physical EOF of data fork}                filRStBlk:                    Integer;                {first alloc. blk. of resource fork}                filRLgLen:                    LongInt;                {logical EOF of resource fork}                filRPyLen:                    LongInt;                {physical EOF of resource fork}                filCrDat:                    LongInt;                {date and time of creation}                filMdDat:                    LongInt;                {date and time of last modification}                filBkDat:                    LongInt;                {date and time of last backup}                filFndrInfo:                    FXInfo;                {additional Finder information}                filClpSize:                    Integer;                {file clump size}                filExtRec:                    ExtDataRec;                {first data fork extent record}                filRExtRec:                    ExtDataRec;                {first resource fork extent record}                filResrv:                    LongInt);                {reserved}cdrThdRec:                                                    {directory thread record}              (thdResrv:                        ARRAY[1..2] OF LongInt;                                                    {reserved}                thdParID:                    LongInt;                {parent ID for this directory}                thdCName:                    Str31);                {name of this directory}cdrFThdRec:                                                    {file thread record}              (fthdResrv:                        ARRAY[1..2] OF LongInt;                                                    {reserved}                fthdParID:                    LongInt;                {parent ID for this file}                fthdCName:                    Str31);                {name of this file}END;The first two fields of a catalog data record are common to all four variants: Each variant also includes its own unique fields.Fields descriptions common to all variantscdrType    The type of catalog data record. This field can contain one of four values:    Value    Meaning    1    Directory record    2    File record    3    Directory thread record    4    File thread recordcdrResrv2    Reserved.Fields descriptions for the cdrDirRec variantdirFlags    Directory flags. dirVal    The directory valence (the number of files in this directory).dirDirID    The directory ID.dirCrDat    The date and time this directory was created.dirMdDat    The date and time this directory was last modified.dirBkDat    The date and time this directory was last backed up.dirUsrInfo    Information used by the Finder.dirFndrInfo    Additional information used by the Finder.dirResrv    Reserved.Fields descriptions for the cdrFilRec variantfilFlags    File flags.  This is interpreted as a bitmap; currently the following bits are defined:    Bit    Meaning    0    If set, file is locked and cannot be written to.    1    If set, a file thread record exists for this file.    7    If set, the file record is used. Huh?filTyp    The file type. This field should always contain 0.filUsrWds    The file’s Finder information.filFlNum    The file ID.filStBlk    The first allocation block of the data fork.filLgLen    The logical EOF of the data forkfilPyLen    The physical EOF of the data fork.filRStBlk    The first allocation block of the resource fork.filRLgLen    The logical EOF of the resource forkfilRPyLen    The physical EOF of the resource fork.filCrDat    The date and time this file was created.filMdDat    The date and time this file was last modified.filBkDat    The date and time this file was last backed up.filFndrInfo    Additional information used by the Finder.filClpSize    The file clump size.filExtRec    The first extent record of the file’s data fork.filRExtRec    The first extent record of the file’s resource fork.filResrv    Reserved.Fields descriptions for the cdrThdRec variantthdResrv    Reserved. thdParID    The directory ID of the parent of the associated directory.thdCName    The name of this directory.Fields descriptions for the cdrFThdRec variantfthdResrv    Reserved. fthdParID    The directory ID of the parent of the associated file.fthdCName    The name of this file.As you can see, a file thread record is exactly the same as a directory thread record except that the associated object is a file, not a directory.Extents Overflow FilesThe File Manager keeps track of which allocation blocks belong to a file by maintaining a list of contiguous disk segments that belong to that file, in the appropriate order. When the list of disk segments gets too large, some of those segments (or extents) are stored on disk in a file called the extents overflow file.The structure of an extents overflow file is relatively simple compared to that of a catalog file. The function of the extents overflow file is to store those file extents that are not contained in the MDB or VCB (in the case of the catalog and extents overflow files themselves) or in an FCB (in the case of all other files). Because the first three file extents are always maintained in memory (in a VCB or an FCB), the File Manager needs to read the extents overflow file only to retrieve any file extents beyond the first three; if a file has at most three extents, the File Manager never needs to read the disk to find the file’s blocks. (This is the one good reason to promote file block contiguity.)An extent is a contiguous range of allocation blocks that have been allocated to some file. You can represent the structure of an extent using an extent descriptor record:TYPE ExtDescriptor                                            =            {extent descriptor}RECORD                xdrStABN:                    Integer;                    {first allocation block}                xdrNumABlks:                    Integer;                    {number of allocation blocks}END;An extent descriptor record consists of the first allocation block of the extent, followed by the number of allocation blocks in that extent. The File Manager prefers to access extent descriptors in groups of three; to do so, it uses the extent data record, defined by the ExtDataRec data type.TYPE                ExtDataRec    :            ARRAY[1..3] of ExtDescriptor;    {extent data record}Recall that the drCTExtRec and drXTExtRec fields of the MDB are of type ExtDataRec (see “Master Directory Blocks” earlier in this chapter), as is the fcbExtRec field of an FCB (see “File Control Blocks” earlier in this chapter). Also, the records in the leaf nodes of the extents overflow file are extent data records. This is what makes the extents overflow file much simpler than the catalog file: the data in a leaf node of an extents overflow file always consists of a single kind of record, instead of the four kinds of records found in a catalog file.The other main difference between a catalog B*-tree and an extents overflow B*-tree concerns the format of the key. The extent record key can be described with the ExtKeyRec data type:TYPE ExtKeyRec                                    =                    {extent key record}RECORD                xkrKeyLen:                    SignedByte;                    {key length}                xkrFkType:                    SignedByte;                    {fork type}                xkrFNum:                    LongInt;                    {file number}                xkrFABN:                    Integer;                    {starting file allocation block}END;xkrKeyLen    The length (in bytes) of the rest of the key. In the current implementation, this field always contains the value 7.xfrFkType    The type of file fork. This field contains $00 if the file is a data fork and $FF if the file is a resource fork.xkrFNum    The file ID of the file.xkrFABN    The starting file allocation block number. This number is the index in the list of the allocation blocks belonging to this file of the first allocation block of the first extent descriptor of the extent record.Disks initialized using the enhanced Disk Initialization Package introduced in system software version 7.0 might contain extent records for some blocks that do not belong to any actual file in the file system. These extent records have a file ID set to 5, indicating that the extent contains a bad block. See the “Disk Initialization Package” chapter in this volume for details on bad block sparing.<36pt\>\x12 <8bat\>uData Organization in MemoryThis section describes the data structures used internally by the File Manager and any external file system that accesses files on Macintosh-initialized volumes. As with the information described earlier in “Data Organization on Disk”, most applications do not need to access these internal data structures directly. In general, you need to know about these data structures only if you are writing an external file system or a disk utility.This section is provided primarily for informational purposes. The organization of data in memory is subject to change. If you want your application to be compatible with future versions of Macintosh system software, you should not access these internal data structures directly.<36pt\>\x12 <8bat\>sThe data structures maintained in memory by the File Manager and external file systems includen    the file I/O queuen    the volume control block queue, listing information about each mounted volumen    the file control block buffer, listing information about each access path to a forkn    volume buffers (one for each on-line volume)n    a B*-tree control block for the catalog file and the extents overflow file for each mounted volumen    the drive queue, listing information about each drive connected to the MacintoshThe File I/O QueueThe file I/O queue is a standard Operating System queue (described in the Operating System Utilities chapter in this volume) that contains parameter blocks for all asynchronous routines awaiting execution.Each entry in the file I/O queue consists of a parameter block for the routine that was called. The first four fields of each parameter block are used by the File Manager in processing the I/O requests in the queue:TYPE ParamBlockRec =RECORD                qLink:                    QElemPtr;                    {next queue entry}                qType:                    Integer;                    {queue type}                ioTrap:                    Integer;                    {routine trap}                ioCmdAddr:                    Ptr;                    {routine address}                . . .                                        {rest of block}END;qLink    A pointer to the next entry in the file I/O queue.qType    The queue type. This field must always contain ORD(ioQType).ioTrap    The trap word of the routine that was called.ioCmdAddr    The address of the routine that was called.You can get a pointer to the header of the file I/O queue by calling the File Manager utility function GetFSQHdr.ASSEMBLY LANGUAGE NOTEThe global variable FSQHdr contains the header of the file I/O queue.<36pt\>\x12 <8bat\>uVolume Control BlocksEach time a volume is mounted, the File Manager reads its volume information from the master directory block and uses the information to build a new volume control block (VCB) in the volume control block queue (unless an ejected or off-line volume is being remounted). The File Manager also creates a volume buffer in the system heap. When a volume is placed off-line, its buffer is released. When a volume is unmounted, its VCB is removed from the VCB queue as well.ASSEMBLY LANGUAGE NOTEThe global variable VCBQHdr contains the header of the VCB queue. The global variable DefVCBPtr points to the default volume’s volume control block.<36pt\>\x12 <8bat\>uThe size and structure of a VCB may be different in future versions of Macintosh system software. To ensure that you are reading the correct version of a VCB, check the vcbSigWord field; it should contain the value $4244.<36pt\>\x12 <8bat\>sThe volume control block queue is a standard Operating System queue that’s maintained in the system heap. It contains a volume control block for each mounted volume. A volume control block is a 178-byte nonrelocatable block that contains volume-specific information. The structure of a volume control block is defined by the VCB data type.    TYPE VCB                             =                {volume control block}    RECORD                qLink:                        QElemPtr;                {next queue entry}        qType:                        Integer;                {queue type}        vcbFlags:                        Integer;                {volume flags}        vcbSigWord:                        Integer;                {volume signature}        vcbCrDate:                        LongInt;                {date and time of volume creation}        vcbLsMod:                        LongInt;                {date and time of last modification}        vcbAtrb:                        Integer;                {volume attributes}        vcbNmFls:                        Integer;                {number of files in root directory}        vcbVBMSt:                        Integer;                {first block of volume bitmap}        vcbAllocPtr:                        Integer;                {start of next allocation search}        vcbNmAlBlks:                        Integer;                {number of allocation blocks in volume}        vcbAlBlkSiz:                        LongInt;                {size (in bytes) of allocation blocks}        vcbClpSiz:                        LongInt;                {default clump size}        vcbAlBlSt:                        Integer;                {first allocation block in volume}        vcbNxtCNID:                        LongInt;                {next unused catalog node ID}        vcbFreeBks:                        Integer;                {number of unused allocation blocks}        vcbVN:                        String[27];                {volume name}        vcbDrvNum:                        Integer;                {drive number}        vcbDRefNum:                        Integer;                {driver reference number}        vcbFSID:                        Integer;                {file-system identifier}        vcbVRefNum:                        Integer;                {volume reference number}        vcbMAdr:                        Ptr;                {used internally}        vcbBufAdr:                        Ptr;                {used internally}        vcbMLen:                        Integer;                {used internally}        vcbDirIndex:                        Integer;                {used internally}        vcbDirBlk:                        Integer;                {used internally}        vcbVolBkUp:                        LongInt;                {date and time of last backup}        vcbVSeqNum:                        Integer;                {volume backup sequence number}        vcbWrCnt:                        LongInt;                {volume write count}        vcbXTClpSiz:                        LongInt;                {clump size for extents overflow file}        vcbCTClpSiz:                        LongInt;                {clump size for catalog file}        vcbNmRtDirs:                        Integer;                {number of directories in root dir.}        vcbFilCnt:                        LongInt;                {number of files in volume}        vcbDirCnt:                        LongInt;                {number of directories in volume}        vcbFndrInfo:                        ARRAY[1..8] OF LongInt;                                                {information used by the Finder}        vcbVCSize:                        Integer;                {used internally}        vcbVBMCSiz:                        Integer;                {used internally}        vcbCtlCSiz:                        Integer;                {used internally}        vcbXTAlBlks:                        Integer;                {size of extents overflow file}        vcbCTAlBlks:                        Integer;                {size of catalog file}        vcbXTRef:                        Integer;                {ref. num. for extents overflow file}        vcbCTRef:                        Integer;                {ref. num. for catalog file}        vcbCtlBuf:                        Ptr;                {ptr. to extents and catalog caches}        vcbDirIDM:                        LongInt;                {directory last searched}        vcbOffsM:                        Integer;                {offspring index at last search}    END;The values in the vcbNmAlBlks and vcbFreeBks fields are unsigned integers (that is, they can range from 0 to 65,535, not from –32,768 to 32,767). Pascal does not support unsigned data types, so you need to use the technique illustrated in “Determining the Amount of Free Space on a Volume” to correctly read the values in these fields.<36pt\>\x12 <8bat\>uqLink    A pointer to the next entry in the VCB queue. You can get a pointer to the header of the VCB queue by calling the File Manager utility function GetVCBQHdr.qType    The queue type. This field must always contain ORD(fsQType).vcbFlags    Volume flags. Bit 15 is set if the volume information has been changed by a routine call since the volume was last affected by a FlushVol call.vcbSigWord    The volume signature. For HFS volumes, this field contains $4244.vcbCrDate    The date and time of volume creation (initialization).vcbLsMod    The date and time of last modification. This is not necessarily when the volume was last flushed.vcbAtrb    Volume attributes. Currently the following bits are defined:    Bit    Meaning    0–4    Reserved    6    Set if the volume is busy (one or more files are open)    7    Set if the volume is locked by hardware    15    Set if the volume is locked by softwarevcbNmFls    The number of files in the root directory.vcbVBMSt    The first block of the volume bitmap.vcbAllocPtr    The start block of the next allocation search. Used internally.vcbNmAlBlks    The number of allocation blocks in the volume.vcbAlBlkSiz    The allocation block size (in bytes). This value must always be a multiple of 512 bytes.vcbClpSiz    The default clump size.vcbAlBlSt    The first allocation block in the volume.vcbNxtCNID    The next unused catalog node ID (directory ID or file ID).vcbFreeBks    The number of unused allocation blocks on the volume.vcbVN    The volume name. This field consists of a length byte followed by 27 bytes. Note that the volume name can occupy at most 27 characters; this is an exception to the normal file and directory name limit of 31 characters.vcbDrvNum    The drive number of the drive on which the volume is mounted. When a mounted volume is placed off-line or ejected, vcbDrvNum is cleared.vcbDRefNum    The driver reference number of the driver used to access the volume. When a volume is ejected, vcbDRefNum is set to the negative of vcbDrvNum (becoming a positive number).vcbFSID    An identifier for the file system handling the volume; it’s 0 for volumes handled by the File Manager, and nonzero for volumes handled by other file systems.vcbVRefNum    The volume reference number.vcbMAdr    Used internally.vcbBufAdr    Used internally.vcbMLen    Used internally.vcbDirIndex    Used internally.vcbDirBlk    Used internally.vcbVolBkUp    The date and time of the last volume backup.vcbVSeqNum    Used internally.vcbWrCnt    The volume write count.vcbXTClpSiz    The clump size of the extents overflow file.vcbCTClpSiz    The clump size of the catalog file.vcbNmRtDirs    The number of directories in the root directory.vcbFilCnt    The number of files on the volume.vcbDirCnt    The number of directories on the volume.vcbFndrInfo    Information used by the Finder.vcbVCSize    Used internally.vcbVBMCSiz    Used internally.vcbCtlCSiz    Used internally.vcbXTAlBks    The size (in blocks) of the extents overflow file.vcbCTAlBks    The size (in blocks) of the catalog file.vcbXTRef    The path reference number for the extents overflow file.vcbCTRef    The path reference number for the catalog file.vcbCtlBuf    A pointer to the extents and catalog caches.vcbDirIDM    The directory last searched.vcbOffsM    The offspring index at the last search.File Control BlocksEach time a file is opened, the File Manager reads that file’s catalog entry and builds a file control block (FCB) in the FCB buffer, which contains information about all access paths. The FCB buffer is a block in the system heap; the first word contains the length of the buffer and the remainder of the buffer is used to hold FCBs for open files.The initial size of the FCB buffer is determined by the system startup information stored on a volume. (See “Boot Blocks” earlier in this chapter for details on the system startup information.) Beginning in system software version 7.0, the File Manager attempts to resize the FCB buffer whenever the existing buffer is filled.You can find the beginning of any particular FCB by adding the size of all preceding FCBs to the size of the FCB buffer length word (that is, 2). This offset from the head of the FCB buffer is used as the file reference number of the corresponding open file. The current size of an FCB is 94 bytes, so the first few valid file reference numbers are 2, 96, 190, 284, 378, 472, and so on. The maximum size of a growable FCB buffer is 32,535 bytes, so there is an absolute limit of 342 FCBs in the FCB buffer.The size and structure of an FCB will be different in future versions of Macintosh system software. To be safe, you should get information from the FCB allocated for an open file by calling the File Manager function PBGetFCBInfo.<36pt\>\x12 <8bat\>uWhen you close a file (for example, by calling FSClose), the FCB for that file is cleared and the File Manager may use that space to hold the FCB for a file that is opened at a later time. Consequently, it is important that you do not attempt to close a file more than once; you may inadvertently close a file that was opened by the system or by another application.Closing a volume’s catalog file (perhaps by inadvertently calling FSClose or PBClose twice with the same file reference number) may result in damage to the volume’s file system and loss of data.<36pt\>\x12 <8bat\>sThe structure of a file control block is defined by the FCB data type.TYPE FCB                            =                        {file control block}RECORD                fcbFlNum:                    LongInt;                {file ID}                fcbFlags:                    Integer;                {file flags}                fcbSBlk:                    Integer;                {reserved}                fcbEOF:                    LongInt;                {logical end-of-file}                fcbPLen:                    LongInt;                {physical end-of-file}                fcbCrPs:                    LongInt;                {current file mark position}                fcbVPtr:                    Ptr;                {pointer to volume control block}                fcbBfAdr:                    Ptr;                {pointer to access path buffer}                fcbFlPos:                    Integer;                {reserved}                fcbClmpSize:                    LongInt;                {file clump size}                fcbBTCBPtr:                    Ptr;                {pointer to B*-tree control block}                fcbExtRec;                    ExtDataRec;                {first three file extents}                fcbFType:                    LongInt;                {file’s four Finder type bytes}                fcbCatPos:                    LongInt;                {catalog hint for use on close}                fcbDirID:                    LongInt;                {file’s parent directory ID}                fcbCName:                    String[31];                {name of file}END;fcbFlNum    The file ID of this file.fcbFlags    Flags describing the status of the file. Currently the following bits are defined:    Bit    Meaning    0–7    Reserved    8    Set if data can be written to the file    9    Set if this FCB describes a resource fork    10    Set if the file has a locked byte range    11    Reserved    12    Set if the file has shared write permissions    13    Set if the file is locked (write-protected)    14    Set if the file’s clump size is specified in the FCB    15    Set if the file has changed since it was last flushedfcbSBlk    Reserved.fcbEOF    The logical end-of-file of the file.fcbPLen    The physical end-of-file of the file.fcbCrPs    The position of the mark.fcbVPtr    A pointer to the volume control block of the volume containing the file.fcbBfAdr    A pointer to the file’s access path buffer.fcbFlPos    Reserved.fcbClmpSize    The clump size of the file.fcbBTCBPtr    A pointer to the file’s B*-tree control block.fcbExtRec    An extent record (12 bytes) containing the first three extents of the file.fcbFType    The file’s Finder type.fcbCatPos    A catalog hint, used when you close the file.fcbDirID    The file’s parent directory ID.fcbCName    The file’s name (as contained in the volume catalog).B*-Tree Control BlocksWhen the File Manager mounts a volume, it reads the B*-tree header node for both the catalog file and the extents overflow file found on that volume and, for each file, creates a B*-tree control block in memory. (See the section “Header Nodes” earlier in this chapter for a description of B*-tree header nodes.) The structure of a B*-tree control block is defined by the BTCB data type.TYPE BTCB                                    =                {B*-tree control block}RECORD                btcFlags:                    SignedByte;                {flag byte}                btcResv:                    SignedByte;                {reserved}                btcRefNum:                    Integer;                {file reference number}                btcKeyCr:                    ProcPtr:                {pointer to key comparison routine}                btcCQPtr:                    LongInt;                {pointer to cache queue}                btcVarPtr:                    LongInt;                {pointer to B*-tree variables}                btcLevel:                    Integer;                {current level}                btcNodeM:                    LongInt;                {current node mark}                btcIndexM:                    Integer;                {current index mark}                btcDepth:                    Integer;                {current depth of tree}                btcRoot:                    LongInt;                {number of root node}                btcNRecs:                    LongInt;                {number of leaf records in tree}                btcFNode:                    LongInt;                {number of first leaf node}                btcLNode:                    LongInt;                {number of last leaf node}                btcNodeSize:                    Integer;                {size of a node}                btcKeyLen:                    Integer;                {maximum length of a key}                btchNNodes:                    LongInt;                {total number of nodes in tree}                btcFree:                    LongInt;                {number of free nodes}END;btcFlags    A flag byte. Currently the following bits are defined:    Bit    Meaning    4    Set if an existing index record must be deleted    5    Set if a new index record must be created    6    Set if the index key must be updated    7    Set if the block has changed since it was last flushedbtcResv    Reserved.btcRefNum    The file reference number of the catalog or extents overflow file corresponding to this control block.btcKeyCr    A pointer to the routine used to compare keys.btcCQPtr    A pointer to the cache queue.btcVarPtr    A pointer to B*-tree variables. btcLevel    The current level.btcNodeM    The current node mark.btcIndexM    The current index mark.bthDepth    The current depth of the B*-tree.btcRoot    The node number of the root node. The root node is the start of the B*-tree structure; usually the root node is first index node, but it might be a leaf node if there are no index nodes.btcNRecs    The number of data records (records contained in leaf nodes).btcFNode    The node number of the first leaf node.btcLNode    The node number of the last leaf node.btcNodeSize    The size (in bytes) of a node. Currently, this is always 512.btcKeyLen    The length of the key records in each node.btcNNodes    The total number of nodes in the B*-tree.btcFree    The total number of free nodes in the B*-tree.The Drive QueueThe File Manager maintains a list of all disk drives connected to the Macintosh in the drive queue, which is a standard operating system queue. The drive queue is initially created at system startup time. Elements are added to the queue at system startup time or when you call the AddDrive function. The drive queue can support any number of drives, limited only by memory space. Each element in the drive queue contains information about the corresponding drive; the structure of a drive queue element is defined by the DrvQEl data type.TYPE DrvQEl =RECORD                qLink:                    QElemPtr;                {next queue entry}                qType:                    Integer;                {flag for dQDrvSz and dQDrvSz2}                dQDrive:                    Integer;                {drive number}                dQRefNum:                    Integer;                {driver reference number}                dQFSID:                    Integer;                {file-system identifier}                dQDrvSz:                    Integer;                {number of logical blocks on drive}                dQDrvSz2:                    Integer;                {additional field for large drives}END;qLink    A pointer to the next entry in the drive queue.qType    Used to specify the size of the drive. If qType is 0, the number of logical blocks on the drive is contained in the dQDrvSz field alone. If qType is 1, both dQDrvSz and dQDrvSz2 are used to store the number of blocks; in that case, dQDrvSz2 contains the high-order word of this number and dQDrvSz contains the low-order word.dQDrive    The drive number of the drive.dQRefNum    The driver reference number of the driver controlling the device on which the volume is mounted.dQFSID    An identifier for the file system handling the volume in the drive; it’s 0 for volumes handled by the File Manager and nonzero for volumes handled by other file systems.dQDrvSz    The number of logical blocks on the drive.dQDrvSz2    An additional field to handle large drives. This field is used only if the qType field contains 1.The File Manager also maintains 4 flag bytes preceding each drive queue element. These bytes contain the following information:Byte    Contents0    Bit 7=1 if the volume on the drive is locked1    0 if no disk in drive; 1 or 2 if disk in drive; 8 if nonejectable    disk in drive; $FC-$FF if disk was ejected within last 1.5     seconds; $48 if disk in drive is nonejectable but driver wants a call2    Used internally during system startup3    Bit 7=0 if disk is single-sidedYou can read these flags by subtracting 4 bytes from the beginning of a drive queue element, as illustrated in Listing 2-10.Reading a drive queue element’s flag bytesFUNCTION GetDriveFlags (myDQElemPtr: DrvQElPtr): LongInt;TYPE                FlagPtr = ^LongInt;                            {pointer to the queue element flag bytes}VAR                myQFlagsPtr:                    FlagPtr;BEGIN                {just subtract 4 from the queue element pointer}                myQFlagsPtr := FlagPtr(ORD4(myDQElemPtr) - 4);                GetDriveFlags := myQFlagsPtr^;END;The GetDriveFlags function defined Listing 2-10 takes a pointer to a drive queue element as a parameter. You can get a queue element pointer for a particular volume by walking the drive queue until you find a queue element whose dQDrive field contains the same value as the vcbDrvNum field of that volume’s VCB. You can get a pointer to the header of the drive queue by calling the File Manager function GetDrvQHdr.Note that the bit numbers given in this section use the standard MC68000 numbering scheme; to access the correct bit using some Pascal routines, you must reverse that numbering. For example, to determine whether a particular disk is single-sided using the Toolbox BitTst routine, you must test bit 24 (that is, 31–7) of the returned long integer. If you use the built-in Pascal function BTST, however, you can test the indicated bit directly.ASSEMBLY LANGUAGE NOTEThe global variable DrvQHdr contains the header of the drive queue.<36pt\>\x12 <8bat\>uReference to the File ManagerThis section describes the routines provided by the File Manager and the data structures you must pass when calling those routines.Data StructuresThis section describes the data structures that your application uses to exchange information with the File Manager. See the sections “Data Organization on Disk” and “Data Organization in Memory” for a description of the data structures that the File Manager uses to maintain information on disk or in memory.File System Specification RecordThe system software recognizes the file system specification record, which provides a simple, standard way to specify the name and location of a file or directory. The file system specification record is defined by the FSSpec data type:TYPE FSSpec                             =                    {file system specification}RECORD                vRefNum:                Integer;                {volume reference number}                parID:                LongInt;                {directory ID of parent directory}                name:                Str63;                {filename or directory name}END;vRefNum    The volume reference number of the volume containing the specified file or directory.parID    The directory ID of the directory containing the specified file or directory.name    The name of the specified file or directory.The FSSpec record can describe only a file or a directory, not a volume. A volume can be identified by its root directory, although the system software never uses an FSSpec record to describe a volume. (The directory ID of the root’s parent directory is fsRtParID, defined in the interface files. The name of the root directory is the same as the name of the volume.)If you need to convert a file specification into an FSSpec record, call the function FSMakeFSSpec. Do not fill in the fields of an FSSpec record yourself.Basic File Manager Parameter BlockMany of the low-level functions that manipulate files and volumes exchange information with your application using the basic File Manager parameter block, defined by the ParamBlockRec data type.TYPE    ParamBlockRec                        =                        {basic File Manager parameter block}RECORD                qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {queue type}        ioTrap:                        Integer;                    {routine trap}        ioCmdAddr:                        Ptr;                    {routine address}        ioCompletion:                        ProcPtr;                    {completion routine}        ioResult:                        OSErr;                    {result code}        ioNamePtr:                        StringPtr;                    {pointer to pathname}        ioVRefNum:                        Integer;                    {volume specification}    CASE ParamBlkType OF    ioParam:                          (ioRefNum:                            Integer;                    {file reference number}        ioVersNum:                        SignedByte;                    {version number}        ioPermssn:                        SignedByte;                    {read/write permission}        ioMisc:                        Ptr;                    {miscellaneous}        ioBuffer:                        Ptr;                    {data buffer}        ioReqCount:                        LongInt;                    {requested number of bytes}        ioActCount:                        LongInt;                    {actual number of bytes}        ioPosMode:                        Integer;                    {positioning mode and newline char.}        ioPosOffset:                        LongInt);                    {positioning offset}    fileParam:                          (ioFRefNum:                            Integer;                    {file reference number}        ioFVersNum:                        SignedByte;                    {file version number (unused)}        filler1:                        SignedByte;                    {reserved}        ioFDirIndex:                        Integer;                    {directory index}        ioFlAttrib:                        SignedByte;                    {file attributes}        ioFlVersNum:                        SignedByte;                    {file version number (unused)}        ioFlFndrInfo:                        FInfo;                    {information used by the Finder}        ioFlNum:                        LongInt;                    {file ID}        ioFlStBlk:                        Integer;                    {first alloc. blk. of data fork}        ioFlLgLen:                        LongInt;                    {logical EOF of data fork}        ioFlPyLen:                        LongInt;                    {physical EOF of data fork}        ioFlRStBlk:                        Integer;                    {first alloc. blk. of resource fork}        ioFlRLgLen:                        LongInt;                    {logical EOF of resource fork}        ioFlRPyLen:                        LongInt;                    {physical EOF of resource fork}        ioFlCrDat:                        LongInt;                    {date and time of creation}        ioFlMdDat:                        LongInt);                    {date and time of last modification}    volumeParam:                          (filler2:                            LongInt;                    {reserved}        ioVolIndex:                        Integer;                    {volume index}        ioVCrDate:                        LongInt;                    {date and time of initialization}        ioVLsBkUp:                        LongInt;                    {date and time of last modification}        ioVAtrb:                        Integer;                    {volume attributes}        ioVNmFls                        Integer;                    {number of files in root directory}        ioVDirSt:                        Integer;                    {first block of directory}        ioVBlLn:                        Integer;                    {length of directory in blocks}        ioVNmAlBlks:                        Integer;                    {number of allocation blocks}        ioVAlBlkSiz:                        LongInt;                    {size of allocation blocks}        ioVClpSiz:                        LongInt;                    {number of bytes to allocate}        ioAlBlSt:                        Integer;                    {first block in block map}        ioVNxtFNum:                        LongInt;                    {next unused file ID}        ioVFrBlk:                        Integer);                    {number of unused allocation blocks}    END;The first eight fields are common to all three variants. Each variant also includes its own unique fields.Field descriptions for fields common to all variantsqLink    A pointer to the next entry in the file I/O queue. (This field is used internally by the File Manager to keep track of asynchronous calls awaiting execution.)qType    The queue type. (This field is used internally by the File Manager.)ioTrap    The trap number of the routine that was called. (This field is used internally by the File Manager.)ioCmdAddr    The address of the routine that was called. (This field is used internally by the File Manager.)ioCompletion    A pointer to a completion routine to be executed at the end of an asynchronous call. It should be NIL for asynchronous calls with no completion routine, and is automatically set to NIL for all synchronous calls.ioResult    The result code of the function. For synchronous calls, this field is the same as the result code of the function call itself. To determine when an asynchronous call has actually completed, your application can poll this field; it’s set to a positve number when the call is made, and receives the actual result code upon completion of the call.ioNamePtr    A pointer to a pathname. Whenever a routine description specifies that ioNamePtr is used—whether for input, output, or both—it’s very important that you set this field to point to storage for a Str255 (if you’re using a pathname) or to NIL (if you’re not).ioVRefNum    A volume specification (volume reference number, working directory reference number, drive number, or 0 for default volume).Field descriptions for the ioParam variantioRefNum    The file reference number of an open fileioVersNum    A version number. This field is no longer used and you should always set it to 0.ioPermssn    The access mode.ioMisc    Depends on the routine called. This field contains either a new logical end-of-file, a new version number, or a pointer to a new pathname. Because ioMisc is of type Ptr, you’ll need to perform type coercion to interpret the value of ioMisc correctly when it contains an end-of-file (a LongInt) or version number (a SignedByte).ioBuffer    A pointer to a data buffer into which data is written by _Read calls and from which data is read by _Write calls.ioReqCount    The requested number of bytes to be read, written, or allocated.ioActCount    The number of bytes actually read, written, or allocated.ioPosMode    The positioning mode for setting the mark. Bits 0 and 1 of this field indicate how to position the mark; you can use the following predefined constants to set or test their value:                                CONST                                    fsAtMark                    =    0;    {at current mark}                                    fsFromStart                    =    1;    {from beginning of file}                                    fsFromLEOF                    =    2;    {from logical end-of-file}                                    fsFromMark                    =    3;    {relative to current mark}    You can set bit 4 of the ioPosMode field to request that the data be cached, and you can set bit 5 to request that the data not be cached. You can set bit 6 to request that any data written be immediately read; this ensures that the data written to a volume exactly matches the data in memory. To request a read-verify operation, add the following constant to the positioning mode:                                CONST                                    rdVerify                    =    64;        {use read-verify mode}    You can set bit 7 to read a continuous stream of bytes, and place the ASCII code of a newline character in the high-order byte to terminate a read operation at the end of a line.ioPosOffset    The offset to be used in conjunction with the positioning mode. Field descriptions for the fileParam variantioFRefNum    The file reference number of an open file.ioFVersNum    A file version number. This field is no longer used and you should always set it to 0.filler1    Reserved.ioFDirIndex    An index for use with the PBHGetFInfo function.ioFlAttrib    File attributes. The bits in this field have these meanings:    Bit    Meaning    0    Set if file is locked    2    Set if resource fork is open     3    Set if data fork is open    4    Set if a directory    7    Set if file (either fork) is openioFlVersNum    A file version number. This feature is no longer supported and you must always set this field to 0.ioFlFndrInfo    Information used by the Finder. (See the Finder Interface chapter in the Toolbox volume for details.)ioFlNum    A file ID.ioFlStBlk    The first allocation block of the data fork. This field contains 0 if the file’s data fork is empty.ioFlLgLen    The logical end-of-file of the data fork.ioFlPyLen    The physical end-of-file of the data fork.ioFlRStBlk    The first allocation block of the resource fork. This field contains 0 if the file’s resource fork is empty.ioFlRLgLen    The logical end-of-file of the resource fork.ioFlRPyLen    The physical end-of-file of the resource fork.ioFlCrDat    The date and time of the file’s creation, specified in seconds since midnight, January 1, 1904.ioFlMdDat    The date and time of the last modification to the file, specified in seconds since midnight, January 1, 1904.Field descriptions for the volumeParam variantfiller2    Reserved.ioVolIndex    The volume index.ioVCrDate    The date and time of volume initialization.ioVLsBkUp    The date and time the volume information was last modified (This field is not changed when information is written to a file and does not necessarily indicate when the volume was flushed.)ioVAtrb    The volume attributes.ioVNmFls    The number of files in the root directory.ioVDirSt    The first block of the volume directory.ioVBlLn    Length of directory in blocks.ioVNmAlBlks    The number of allocation blocks.ioVAlBlkSiz    The size of allocation blocks.ioVClpSiz    The volume clump size.ioAlBlSt    The first block in volume map.ioVNxtFNum    The next unused file number.ioVFrBlk    The number of unused allocation blocks.HFS Parameter BlockMost of the low-level HFS functions exchange information with your application using the HFS parameter block, defined by the HParamBlockRec data type.TYPE HParamBlockRec                        =         {HFS parameter block}    RECORD                qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {queue type}        ioTrap:                        Integer;                    {routine trap}        ioCmdAddr:                        Ptr;                    {routine address}        ioCompletion:                        ProcPtr;                    {completion routine}        ioResult:                        OSErr;                    {result code}        ioNamePtr:                        StringPtr;                    {pointer to pathname}        ioVRefNum:                        Integer;                    {volume specification}    CASE ParamBlkType OF    ioParam:      (ioRefNum:                            Integer;                    {file reference number}        ioVersNum:                        SignedByte;                    {version number}        ioPermssn:                        SignedByte;                    {read/write permission}        ioMisc:                        Ptr;                    {miscellaneous}        ioBuffer:                        Ptr;                    {data buffer}        ioReqCount:                        LongInt;                    {requested number of bytes}        ioActCount:                        LongInt;                    {actual number of bytes}        ioPosMode:                        Integer;                    {positioning mode and newline char.}        ioPosOffset:                        LongInt);                    {positioning offset}    fileParam:                              (ioFRefNum:                            Integer;                    {file reference number}        ioFVersNum:                        SignedByte;                    {file version number (unused)}        filler1:                        SignedByte;                    {reserved}        ioFDirIndex:                        Integer;                    {directory index}        ioFlAttrib:                        SignedByte;                    {file attributes}        ioFlVersNum:                        SignedByte;                    {file version number (unused)}        ioFlFndrInfo:                        FInfo;                    {information used by the Finder}        ioDirID:                        LongInt;                    {directory ID or file ID}        ioFlStBlk:                        Integer;                    {first alloc. blk. of data fork}        ioFlLgLen:                        LongInt;                    {logical EOF of data fork}        ioFlPyLen:                        LongInt;                    {physical EOF of data fork}        ioFlRStBlk:                        Integer;                    {first alloc. blk. of resource fork}        ioFlRLgLen:                        LongInt;                    {logical EOF of resource fork}        ioFlRPyLen:                        LongInt;                    {physical EOF of resource fork}        ioFlCrDat:                        LongInt;                    {date and time of creation}        ioFlMdDat:                        LongInt);                    {date and time of last modification}    volumeParam:                              (filler2:                            LongInt;                    {reserved}        ioVolIndex:                        Integer;                    {volume index}        ioVCrDate:                        LongInt;                    {date and time of initialization}        ioVLsMod:                        LongInt;                    {date and time of last modification}        ioVAtrb:                        Integer;                    {volume attributes}        ioVNmFls:                        Integer;                    {number of files in root directory}        ioVBitMap:                        Integer;                    {first block of volume bitmap}        ioAllocPtr:                        Integer;                    {first block of next new file}        ioVNmAlBlks:                        Integer;                    {number of allocation blocks}        ioVAlBlkSiz:                        LongInt;                    {size of allocation blocks}        ioVClpSiz:                        LongInt;                    {default clump size}        ioAlBlSt:                        Integer;                    {first block in volume map}        ioVNxtCNID:                        LongInt;                    {next unused node ID}        ioVFrBlk:                        Integer;                    {number of unused allocation blocks}        ioVSigWord:                        Integer;                    {volume signature}        ioVDrvInfo:                        Integer;                    {drive number}        ioVDRefNum:                        Integer;                    {driver reference number}        ioVFSID:                        Integer;                    {file-system identifier}        ioVBkUp:                        LongInt;                    {date and time of last backup}        ioVSeqNum:                        Integer;                    {used internally}        ioVWrCnt                        LongInt;                    {volume write count}        ioVFilCnt:                        LongInt;                    {number of files on volume}        ioVDirCnt:                        LongInt;                    {number of directories on volume}        ioVFndrInfo:                        ARRAY[1..8] OF LongInt);                                                    {information used by the Finder}    accessParam:      (filler3:                            Integer;                    {reserved}        ioDenyModes:                        Integer;                    {access mode information}        filler4:                        Integer;                    {reserved}        filler5:                        SignedByte;                    {reserved}        ioACUser:                        SignedByte;                    {user access rights}        filler6:                        LongInt;                    {reserved}        ioACOwnerID:                        LongInt;                    {owner ID}        ioACGroupID:                        LongInt;                    {group ID}        ioACAccess:                        LongInt);                    {directory access rights}    objParam:                              (filler7:                            Integer;                    {reserved}        ioObjType:                        Integer;                    {function code}        ioObjNamePtr:                        Ptr;                    {ptr to returned creator/group name}        ioObjID:                        LongInt);                    {creator/group ID}    copyParam:                              (ioDstVRefNum:                            Integer;                    {destination volume identifier}        filler8:                        Integer;                    {reserved}        ioNewName:                        Ptr;                    {pointer to destination pathname}        ioCopyName:                        Ptr;                    {pointer to optional name}        ioNewDirID:                        LongInt);                    {destination directory ID}    wdParam:                              (filler9:                            Integer;                    {reserved}        ioWDIndex:                        Integer;                    {working directory index}        ioWDProcID:                        LongInt;                    {working directory user identifier}        ioWDVRefNum:                        Integer;                    {working directory’s vol. ref. num.}        filler10:                        Integer;                    {reserved}        filler11:                        LongInt;                    {reserved}        filler12:                        LongInt;                    {reserved}        filler13:                        LongInt;                    {reserved}        ioWDDirID:                        LongInt);                    {working directory’s directory ID}    fidParam:                          (filler14:                            LongInt;                    {reserved}        ioDestNamePtr:                        StringPtr;                    {pointer to destination filename}        filler15:                        LongInt;                    {reserved}        ioDestDirID:                        LongInt;                    {destination parent directory ID}        filler16:                        LongInt;                    {reserved}        filler17:                        LongInt;                    {reserved}        ioSrcDirID:                        LongInt;                    {source parent directory ID}        filler18:                        Integer;                    {reserved}        ioFileID:                        LongInt);                    {file ID}    csParam:          (ioMatchPtr:                            FSSpecArrayPtr;                    {pointer to array of matches}        ioReqMatchCount:                        LongInt;                    {max. number of matches to return}        ioActMatchCount:                        LongInt;                    {actual number of matches}        ioSearchBits:                        LongInt;                    {enable bits for matching rules}        ioSearchInfo1:                        CInfoPBPtr;                    {pointer to values and lower bounds}        ioSearchInfo2:                        CInfoPBPtr;                    {pointer to masks and upper bounds}        ioSearchTime:                        LongInt;                    {maximum time to search}        ioCatPosition:                        CatPositionRec;                    {current catalog position}        ioOptBuffer:                        Ptr;                    {pointer to optional read buffer}        ioOptBufSize:                        LongInt);                    {length of optional read buffer}    foreignPrivParam:      (filler21:                                    LongInt;                {reserved}        filler22:                                LongInt;                {reserved}        ioForeignPrivBuffer:                                Ptr;                {privileges data buffer}        ioForeignPrivReqCount:                                LongInt;                {size of buffer}        ioForeignPrivActCount:                                LongInt;                {amount of buffer used}        filler23:                                LongInt;                {reserved}        ioForeignPrivDirID:                                LongInt;                {parent directory ID of }                                                        { foreign file or directory}        ioForeignPrivInfo1:                                LongInt;                {privileges data}        ioForeignPrivInfo2            :                    LongInt;                {privileges data}        ioForeignPrivInfo3:                                LongInt;                {privileges data}        ioForeignPrivInfo4:                                LongInt);                {privileges data}    END;The first eight fields are common to all ten variants. Each variant also includes its own unique fields.Field descriptions common to all variantsqLink    A pointer to the next entry in the file I/O queue. (This field is used internally by the File Manager to keep track of asynchronous calls awaiting execution.)qType    The queue type. (This field is used internally by the File Manager.)ioTrap    The trap number of the routine that was called. (This field is used internally by the File Manager.)ioCmdAddr    The address of the routine that was called. (This field is used internally by the File Manager.)ioCompletion    A pointer to a completion routine to be executed at the end of an asynchronous call. It should be NIL for asynchronous calls with no completion routine, and is automatically set to NIL for all synchronous calls.ioResult    The result code of the function. For synchronous calls, this field is the same as the result code of the function call itself. To determine when an asynchronous call has actually completed, your application can poll this field; it’s set to a positve number when the call is made, and receives the actual result code upon completion of the call.ioNamePtr    A pointer to a pathname. Whenever a routine description specifies that ioNamePtr is used—whether for input, output, or both—it’s very important that you set this field to point to storage for a Str255 (if you’re using a pathname) or to NIL (if you’re not).ioVRefNum    A volume specification (volume reference number, working directory reference number, drive number, or 0 for default volume).Field descriptions for the ioParam variantioRefNum    The file reference number of an open fileioVersNum    A version number. This field is no longer used and you should always set it to 0.ioPermssn    The access mode.ioMisc    Depends on the routine called. This field contains either a new logical end-of-file, a new version number, a pointer to an access path buffer, or a pointer to a new pathname. Because ioMisc is of type Ptr, you’ll need to perform type coercion to interpret the value of ioMisc correctly when it contains an end-of-file (a LongInt) or version number (a SignedByte).ioBuffer    A pointer to a data buffer into which data is written by _Read calls and from which data is read by _Write calls.ioReqCount    The requested number of bytes to be read, written, or allocated.ioActCount    The number of bytes actually read, written, or allocated.ioPosMode    The positioning mode for setting the mark. You can set bit 7 to read a continuous stream of bytes, and place the ASCII code of a newline character in the high-order byte to terminate a read operation at the end of a line.ioPosOffset    The offset to be used in conjunction with the positioning mode. Field descriptions for the fileParam variantioFRefNum    The file reference number of an open file.ioFVersNum    A file version number. This field is no longer used and you should always set it to 0.filler1    Reserved.ioFDirIndex    An index for use with the PBHGetFInfo function.ioFlAttrib    File attributes. The bits in this field have these meanings:    Bit    Meaning    0    Set if file is locked    2    Set if resource fork is open     3    Set if data fork is open    4    Set if a directory    7    Set if file (either fork) is openioFlVersNum    A file version number. This field is no longer used and you should always set it to 0.ioFlFndrInfo    Information used by the Finder. (See the Finder Interface chapter in the Toolbox volume for details.)ioDirID    A directory ID.ioFlStBlk    The first allocation block of the data fork. This field contains 0 if the file’s data fork is empty.ioFlLgLen    The logical end-of-file of the data fork.ioFlPyLen    The physical end-of-file of the data fork.ioFlRStBlk    The first allocation block of the resource fork.ioFlRLgLen    The logical end-of-file of the resource fork.ioFlRPyLen    The physical end-of-file of the resource fork.ioFlCrDat    The date and time of the file’s creation, specified in seconds since midnight, January 1, 1904.ioFlMdDat    The date and time of the last modification to the file, specified in seconds since midnight, January 1, 1904.Field descriptions for the volumeParam variantfiller2    Reserved.ioVolIndex    An index for use with the PBHGetVInfo function.ioVCrDate    The date and time of volume initialization.ioVLsMod    The date and time the volume information was last modified (This field is not changed when information is written to a file and does not necessarily indicate when the volume was flushed.)ioVAtrb    The volume attributes.ioVNmFls    The number of files in the root directory.ioVBitMap    The first block of the volume bitmap.ioAllocPtr    The block at which the next new file starts. Used internally.ioVNmAlBlks    The number of allocation blocks.ioVAlBlkSiz    The size of allocation blocks.ioVClpSiz    The clump size.ioAlBlSt    The first block in volume map.ioVNxtCNID    The next unused catalog node ID.ioVFrBlk    The number of unused allocation blocks.ioVSigWord    A signature word identifying the type of volume; it’s $D2D7 for MFS volumes and $4244 for volumes that support HFS calls.ioDrvInfo    The drive number of the drive containing the volume.ioVDRefNum    For on-line volumes, the reference number of the I/O driver for the drive identified by ioDrvInfo.ioVFSID    The file-system identifier. It indicates which file system is servicing the volume; it’s 0 for File Manager volumes and nonzero for volumes handled by an external file system.ioVBkUp    The date and time the volume was last backed up (it’s 0 if never backed up).ioVSeqNum    Used internally.ioVWrCnt    The volume write count.ioVFilCnt    The total number of files on the volume.ioVDirCnt    The total number of directories (not including the root directory) on the volume.ioVFndrInfo    Information used by the Finder. (See the Finder Interface chapter in the Toolbox volume for details.)Field descriptions for the accessParam variantfiller3    Reserved.ioDenyModes    Access mode information. The bits in this field have these meanings:    Bit    Meaning    0    If set, request read permission.    1    If set, request write permission.    2–3    Reserved; must be zero.    4    If set, deny other readers to this file.    5    If set, deny other writers to this file.    6–15    Reserved; must be zerofiller4    Reserved.filler5    Reserved.ioACUser    The user’s access rights for the specified directory. The bits in this field have the following meanings:    Bit    Meaning    0    Set if user does not have See Folder privileges    1    Set if user does not have See Files privileges    2    Set if user does not have Make Changes privileges    3–6    Reserved; always set to 0    7    Set if user is not owner of the directoryfiller6    Reserved.ioACOwnerID    The owner ID.ioACUserID    The user ID.ioACAccess    The directory access rights.Field descriptions for the objParam variantfiller7    Reserved.ioObjType    A function code. The values passed in this field are determined by the routine you pass this parameter block to.ioObjNamePtr    A pointer to the returned creator/group name.ioObjID    The creator/group ID.Field descriptions for the copyParam variantioDstVRefNum    A volume reference number for the destination volume.filler8    Reserved.ioNewName    A pointer to the destination pathname.ioCopyName    A pointer to an optional name.ioNewDirID    A destination directory ID.Field descriptions for the wdParam variantfiller9    Reserved.ioWDIndex    An index to working directories.ioWDProcID    The working directory user identifier.ioWDVRefNum    The volume reference number for the working directory.filler10    Reserved.filler11    Reserved.filler12    Reserved.filler13    Reserved.ioWDDirID    The working directory’s directory ID.Field descriptions for the fidParam variantfiller14    Reserved.ioDestNamePtr    A pointer to the name of the destination file.filler15    Reserved.ioDestDirID    The destination file’s parent directory ID.filler16    Reserved.filler17    Reserved.ioSrcDirID    The source file’s parent directory ID.filler18    Reserved.ioFileID    The file ID.Field descriptions for the csParam variantioMatchPtr    A pointer to an array in which the file and directory names that match the selection criteria are returned. The array must be large enough to hold the largest possible number of FSSpec records, as determined by the ioReqMatchCount field.ioReqMatchCount    The maximum number of matches to return. This number should be the number of FSSpec records that will fit in the memory pointed to by ioMatchPtr. Use this field to avoid a possible excess of matches for criteria that prove to be too general.ioActMatchCount    The number of actual matches found.ioSearchBits    The fields of the parameter blocks ioSearchInfo1 and ioSearchInfo2 that are relevant to the search. See “Searching a Catalog” on page 2-32 for the values of ioSearchBits.ioSearchInfo1    A pointer to a CInfoPBRec parameter block that contains values and the lower bounds of ranges for the fields selected by ioSearchBits.ioSearchInfo2    A pointer to a second CInfoPBRec parameter block that contains masks and upper bounds of ranges for the fields selected by ioSearchBits.ioSearchTime    A time limit on a search, in Time Manager format. Use this field to limit the run time of a single call to PBCatSearch. A value of 0 imposes no time limit.ioCatPosition    A position in the catalog where searching should begin. Use this field to keep an index into the catalog when breaking PBCatSearch down into a number of smaller searches. This field is valid whenever PBCatSearch exits because it either spends the maximum time allowed by ioSearchTime or finds the maximum number of matches allowed by ioReqMatchCount.    To start at the beginning of the catalog, set the initialize field of ioCatPosition to 0. Before exiting after an interrupted search, PBCatSearch sets that field to the next catalog entry to be searched.    To resume where the previous call stopped, pass the entire CatPosition record returned by the previous call as input to the next.ioOptBuffer    A pointer to an optional read buffer. The ioOptBuffer and ioOptBufSize fields let you specify a part of memory as a read buffer, increasing search speed.ioOptBufSize    The length of the buffer pointed to by ioOptBuffer. Buffer effectiveness varies with models and configurations, but a 16 KB buffer is likely to be optimal. Even a 1 KB buffer provides some performance improvement.Field descriptions for the foreignPrivParam variantfiller21    Reserved.filler22    Reserved.ioForeignPrivBufferA pointer to a buffer containing access-control information about the foreign file system. ioForeignPrivReqCountThe size of the buffer pointed to by the ioForeignPrivBuffer field.ioForeignPrivActCountThe amount of the buffer pointed to by the ioForeignPrivBuffer field that was actually used to hold data.filler23    Reserved.ioForeignPrivDirID    The parent directory ID of the foreign file or directory.ioForeignPrivInfo1    A long word that may contain privileges data.ioForeignPrivInfo2    A long word that may contain privileges data.ioForeignPrivInfo3    A long word that may contain privileges data.ioForeignPrivInfo4    A long word that may contain privileges data.Catalog Information Parameter BlocksThe low-level functions PBGetCatInfo, PBSetCatInfo, and PBCatSearch exchange information with your application using the catalog information parameter block, which is defined by the CInfoPBRec data type. There are two variants of this record, hFileInfo and dirInfo, which describe files and directories, respectively.    TYPE CInfoPBRec                        =    {catalog information parameter block}    RECORD        qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {queue type}        ioTrap:                        Integer;                    {routine trap}        ioCmdAddr:                        Ptr;                    {routine address}        ioCompletion:                        ProcPtr;                    {completion routine}        ioResult:                        OSErr;                    {result code}        ioNamePtr:                        StringPtr;                    {pointer to pathname}        ioVRefNum:                        Integer;                    {volume specification}        ioFRefNum::                        Integer;                    {file reference number}        ioFVersNum:                        SignedByte;                    {version number}        filler1:                        SignedByte;                    {reserved}        ioFDirIndex:                        Integer;                    {directory index}        ioFlAttrib:                        SignedByte;                    {file attributes}        ioACUser:                        SignedByte;                    {directory access rights}    CASE CInfoType OF    hFileInfo:                          (ioFlFndrInfo:                            FInfo;                    {information used by the Finder}        ioDirID:                        LongInt;                    {directory ID or file ID}        ioFlStBlk:                        Integer;                    {first alloc. blk. of data fork}        ioFlLgLen:                        LongInt;                    {logical EOF of data fork}        ioFlPyLen:                        LongInt;                    {physical EOF of data fork}        ioFlRStBlk:                        Integer;                    {first alloc. blk. of resource fork}        ioFlRLgLen:                        LongInt;                    {logical EOF of resource fork}        ioFlRPyLen:                        LongInt;                    {physical EOF of resource fork}        ioFlCrDat:                        LongInt;                    {date and time of creation}        ioFlMdDat:                        LongInt;                    {date and time of last modification}        ioFlBkDat:                        LongInt;                    {date and time of last backup}        ioFlXFndrInfo:                        FXInfo;                    {additional Finder information}        ioFlParID:                        LongInt;                    {file parent directory ID (integer)}        ioFlClpSiz:                        LongInt)    ;                {file's clump size}    dirInfo:      (ioDrUsrWds:                            DInfo;                    {information used by the Finder}        ioDrDirID:                        LongInt;                    {directory ID}        ioDrNmFls:                        Integer;                    {number of files in directory}        filler3:                        ARRAY[1..9] OF Integer;        ioDrCrDat:                        LongInt;                    {date and time of creation}        ioDrMdDat:                        LongInt;                    {date and time of last modification}        ioDrBkDat:                        LongInt;                    {date and time of last backup}        ioDrFndrInfo:                        DXInfo;                    {additional Finder information}        ioDrParID:                        LongInt);                    {directory's parent directory ID}    END;                    The first 14 fields are common to both variants. Each variant also includes its own unique fields.Field descriptions common to both variantsqLink    A pointer to the next entry in the file I/O queue. (This field is used internally by the File Manager to keep track of asynchronous calls awaiting execution.)qType    The queue type. (This field is used internally by the File Manager.)ioTrap    The trap number of the routine that was called. (This field is used internally by the File Manager.)ioCmdAddr    The address of the routine that was called. (This field is used internally by the File Manager.)ioCompletion    A pointer to a completion routine to be executed at the end of an asynchronous call. It should be NIL for asynchronous calls with no completion routine, and is automatically set to NIL for all synchronous calls.ioResult    The result code of the function. For synchronous calls, this field is the same as the result code of the function call itself. To determine when an asynchronous call has actually completed, your application can poll this field; it’s set to a positve number when the call is made, and receives the actual result code upon completion of the call.ioNamePtr    A pointer to a pathname. Whenever a routine description specifies that ioNamePtr is used—whether for input, output, or both—it’s very important that you set this field to point to storage for a Str255 (if you’re using a pathname) or to NIL (if you’re not).ioVRefNum    A volume specification. You can specify a volume using a volume reference number, a drive number, a working directory reference number, or 0 for the default drive.ioFRefNum    The file reference number of an open file.ioFVersNum    A file version number. This field is no longer used and you should always set it to 0.filler1    Reserved.ioFDirIndex    A file and directory index. If this field contains a positive number, PBGetCatInfo returns information about the file or directory having that directory index in the directory specified by the ioVRefNum field. (If ioVRefNum contains a volume reference number, the specified directory is that volume’s root directory.)     If this field contains 0, PBGetCatInfo returns information about the file or directory whose name is specified in the ioNamePtr field and that is located in the directory specified by the ioVRefNum field. (Once again, if ioVRefNum contains a volume reference number, the specified directory is that volume’s root directory.)    If this field contains a negative number, PBGetCatInfo ignores the ioNamePtr field and returns information about the directory specified in the ioDirID field. If both ioDirID and ioVRefNum are 0, PBGetCatInfo returns information about the current default directory.ioFlAttrib    File attributes. The bits in this field that are currently used have the following meanings:    Bit    Meaning    0    Set if file is locked    2    Set if resource fork is open    3    Set if data fork is open    4    Set if a directory    7    Set if file (either fork) is openioACUser    The user’s access rights for the specified directory. The bits in this field have the following meanings:    Bit    Meaning    0    Set if user does not have See Folder privileges    1    Set if user does not have See Files privileges    2    Set if user does not have Make Changes privileges    3–6    Reserved; always set to 0    7    Set if user is not owner of the directory    For example, if you call PBGetCatInfo for a particular shared volume and ioACUser returns 0, you know that the user is the owner of the directory and has complete privileges to it.Field descriptions for the hFileInfo variantioFlFndrInfo    Information used by the Finder. (See the “Finder Interface” chapter in the Toolbox volume for details.)ioDirID    A directory ID or file ID. On input to PBGetCatInfo, this field contains a directory ID (which is used only if the ioFDirIndex field is negative). On output, this field contains the file ID of the specified file.ioFlStBlk    The first allocation block of the data fork. This field contains 0 if the file’s data fork is empty.ioFlLgLen    The logical end-of-file of the data fork.ioFlPyLen    The physical end-of-file of the data fork.ioFlRStBlk    The first allocation block of the resource fork.ioFlRLgLen    The logical end-of-file of the resource fork.ioFlRPyLen    The physical end-of-file of the resource fork.ioFlCrDat    The date and time of the file’s creation, specified in seconds since midnight, January 1, 1904.ioFlMdDat    The date and time of the last modification to the file, specified in seconds since midnight, January 1, 1904.ioFLBkDat    The date and time of the last backup to the file, specified in seconds since midnight, January 1, 1904.ioFlXFndrInfo    Additional information used by the Finder. (See the Finder Interface chapter in the Toolbox volume for details.)ioFlParID    The directory ID of the file’s parent.ioFlClpSiz    The clump size to be used when writing the file; if it’s 0, the volume’s clump size is used when the file is opened. Field descriptions for the dirInfo variantioDrUserWds    Information used by the Finder. (See the Finder Interface chapter in the Toolbox volume for details.)ioDrDirID    A directory ID. On input to PBGetCatInfo, this field contains a directory ID (which is used only if the ioFDirIndex field is negative). On output, this field contains the directory ID of the specified directory.ioDrNmFls    The number of files in the directory.filler3    Reserved.ioDrCrDat    The date and time of the directory’s creation, specified in seconds since midnight, January 1, 1904.ioDrMdDat    The date and time of the last modification to the directory, specified in seconds since midnight, January 1, 1904.ioDrBkDat    The date and time of the last backup to the directory, specified in seconds since midnight, January 1, 1904.ioDrFndrInfo    Additional information used by the Finder. (See the Finder Interface chapter in the Toolbox volume for details.)ioDrParID    The directory ID of the specified directory’s parent.Catalog Position RecordsWhen you call the PBCatSearch function to search a volume’s catalog, you can specify (in the ioCatPosition field of the parameter block passed to PBCatSearch) a catalog position record. If a catalog search consumes more time than is allowed by the ioSearchTime field, PBCatSearch stores a directory-location index in that record; when you call PBCatSearch again, it uses that record to resume searching where it left off. A catalog position record is defined by the CatPositionRec data type:TYPE CatPositionRec                                    =    {catalog position record}RECORD                initialize:                    LongInt;                                {starting point}                priv:                    ARRAY[1..6] OF Integer;                                {private data}END;initialize    The starting point of the catalog search. To start searching at the beginning of a catalog, specify 0 in this field. To resume a previous search, pass the value returned by the previous call to PBCatSearch.priv    An array of integers that is used internally by PBCatSearch.Catalog Move Parameter BlocksThe low-level HFS function PBCatMove uses the catalog move parameter block defined by the CMovePBRec data type.TYPE CMovePBRec                                    =                 {catalog move parameter block}RECORD                qLink:                    QElemPtr;                {next queue entry}                qType:                    Integer;                {queue type}                ioTrap:                    Integer;                {routine trap}                ioCmdAddr:                    Ptr;                {routine address}                ioCompletion:                    ProcPtr;                {completion routine}                ioResult:                    OSErr;                {result code}                ioNamePtr:                    StringPtr;                {pointer to pathname}                ioVRefNum:                    Integer;                {volume specification}                filler1:                    LongInt;                {reserved}                ioNewName:                    StringPtr;                {name of new directory}                filler2:                    LongInt;                {reserved}                ioNewDirID:                    LongInt;                {directory ID of new directory}                filler3:                    ARRAY[1..2] OF LongInt;                                {reserved}                ioDirID:                    LongInt;                {directory ID of current directory}END;qLink    A pointer to the next entry in the file I/O queue. (This field is used internally by the File Manager to keep track of asynchronous calls awaiting execution.)qType    The queue type. (This field is used internally by the File Manager.)ioTrap    The trap number of the routine that was called. (This field is used internally by the File Manager.)ioCmdAddr    The address of the routine that was called. (This field is used internally by the File Manager.)ioCompletion    A pointer to a completion routine to be executed at the end of an asynchronous call. It should be NIL for asynchronous calls with no completion routine, and is automatically set to NIL for all synchronous calls.ioResult    The result code of the function. For synchronous calls, this field is the same as the result code of the function call itself. To determine when an asynchronous call has actually completed, your application can poll this field; it’s set to a positve number when the call is made, and receives the actual result code upon completion of the call.ioNamePtr    A pointer to a pathname. Whenever a routine description specifies that ioNamePtr is used—whether for input, output, or both—it’s very important that you set this field to point to storage for a Str255 (if you’re using a pathname) or to NIL (if you’re not).ioVRefNum    A volume specification (volume reference number, working directory reference number, drive number, or 0 for default volume).filler1    Reserved.ioNewName    The name of the directory to which the specified file or directory is to be moved.filler2    Reserved.ioNewDirID    The directory ID of the directory to which the specified file or directory is to be moved.filler3    Reserved.ioDirID    The current directory ID of the file or directory to be moved (used in conjunction with the ioVRefNum and ioNamePtr fields).Working Directory Parameter BlocksThe low-level HFS functions PBOpenWD, PBCloseWD, and PBGetWDInfo use the working directory parameter block defined by the WDPBRec data type.TYPE WDPBRec                                    =                {working directory parameter block}RECORD                qLink:                    QElemPtr;                {next queue entry}                qType:                    Integer;                {queue type}                ioTrap:                    Integer;                {routine trap}                ioCmdAddr:                    Ptr;                {routine address}                ioCompletion:                    ProcPtr;                {completion routine}                ioResult:                    OSErr;                {result code}                ioNamePtr:                    StringPtr;                {pointer to pathname}                ioVRefNum:                    Integer;                {volume specification}                filler1:                    Integer;                {reserved}                ioWDIndex:                    Integer;                {working directory index}                ioWDProcID:                    LongInt;                {working directory user identifier}                ioWDVRefNum:                    Integer;                {working directory’s vol. ref. num.}                filler2:                    ARRAY[1..7] OF Integer;                                {reserved}                ioWDDirID:                    LongInt;                {working directory's directory ID}END;qLink    A pointer to the next entry in the file I/O queue. (This field is used internally by the File Manager to keep track of asynchronous calls awaiting execution.)qType    The queue type. (This field is used internally by the File Manager.)ioTrap    The trap number of the routine that was called. (This field is used internally by the File Manager.)ioCmdAddr    The address of the routine that was called. (This field is used internally by the File Manager.)ioCompletion    A pointer to a completion routine to be executed at the end of an asynchronous call. It should be NIL for asynchronous calls with no completion routine, and is automatically set to NIL for all synchronous calls.ioResult    The result code of the function. For synchronous calls, this field is the same as the result code of the function call itself. To determine when an asynchronous call has actually completed, your application can poll this field; it’s set to a positve number when the call is made, and receives the actual result code upon completion of the call.ioNamePtr    A pointer to a pathname. Whenever a routine description specifies that ioNamePtr is used—whether for input, output, or both—it’s very important that you set this field to point to storage for a Str255 (if you’re using a pathname) or to NIL (if you’re not).ioVRefNum    A volume specification (volume reference number, working directory reference number, drive number, or 0 for default volume).filler1    Reserved.ioWDIndex    An index for use with the PBGetWDInfo function.ioWDProcID    An identifier that’s used to distinguish between working directories set up by different users; you should use your application’s signature (discussed in the Finder Interface chapter in the Toolbox volume) as the ioWDProcID.ioWDVRefNum    The working directory’s volume reference number.filler2    Reserved.ioWDDirID    The working directory’s directory ID.File Control Block Parameter BlocksThe low-level HFS function PBGetFCBInfo uses the file control block parameter block defined by the FCBPBRec data type:TYPE FCBPBRec                        =            {file control block parameter block}RECORD                qLink:                    QElemPtr;                    {next queue entry}                qType:                    Integer;                    {queue type}                ioTrap:                    Integer;                    {routine trap}                ioCmdAddr:                    Ptr;                    {routine address}                ioCompletion:                    ProcPtr;                    {completion routine}                ioResult:                    OSErr;                    {result code}                ioNamePtr:                    StringPtr;                    {pointer to pathname}                ioVRefNum:                    Integer;                    {volume specification}                ioRefNum:                    Integer;                    {file reference number}                filler:                    Integer;                    {reserved}                ioFCBIndx:                    Integer;                    {FCB index}                filler1                    Integer;                    {reserved}                ioFCBFlNm:                    LongInt;                    {file ID}                ioFCBFlags:                    Integer;                    {flags}                ioFCBStBlk:                    Integer;                    {first allocation block of file}                ioFCBEOF:                    LongInt;                    {logical end-of-file}                ioFCBPLen:                    LongInt;                    {physical end-of-file}                ioFCBCrPs:                    LongInt;                    {position of the file mark}                ioFCBVRefNum:                    Integer;                    {volume reference number}                ioFCBClpSiz:                    LongInt;                    {file's clump size}                ioFCBParID:                    LongInt;                    {parent directory ID}END;qLink    A pointer to the next entry in the file I/O queue. (This field is used internally by the File Manager to keep track of asynchronous calls awaiting execution.)qType    The queue type. (This field is used internally by the File Manager.)ioTrap    The trap number of the routine that was called. (This field is used internally by the File Manager.)ioCmdAddr    The address of the routine that was called. (This field is used internally by the File Manager.)ioCompletion    A pointer to a completion routine to be executed at the end of an asynchronous call. It should be NIL for asynchronous calls with no completion routine, and is automatically set to NIL for all synchronous calls.ioResult    The result code of the function. For synchronous calls, this field is the same as the result code of the function call itself. To determine when an asynchronous call has actually completed, your application can poll this field; it’s set to a positve number when the call is made, and receives the actual result code upon completion of the call.ioNamePtr    A pointer to a pathname. Whenever a routine description specifies that ioNamePtr is used—whether for input, output, or both—it’s very important that you set this field to point to storage for a Str255 (if you’re using a pathname) or to NIL (if you’re not).ioVRefNum    A volume specification (volume reference number, working directory reference number, drive number, or 0 for default volume).ioRefNum    The file reference number of an open file.filler    Reserved.ioFCBIndx    An index for use with the PBGetFCBInfo function.filler1    Reserved.ioFCBFlNm    The file ID.ioFCBFlags    Flags describing the status of the file. The bits in this field that are currently used have the following meanings:    Bit    Meaning    8    Set if data can be written to the file    9    Set if this FCB describes a resource fork    10    Set if the file has a locked byte range    11    Reserved    12    Set if the file has shared write permissions    13    Set if the file is locked (write-protected)    14    Set if the file’s clump size is specified in the FCB    15    Set if the file has changed since it was last flushedioFCBStBlk    The number of the first allocation block of the file.ioFCBEOF    The logical end-of-file.ioFCBPLen    The physical end-of-file.ioFCBCrPs    The position of the file mark.ioFCBVRefNum    The volume reference number.ioFCBClpSiz    The file clump size.ioFCBParID    The file’s parent directory ID.Volume Attributes BufferThe low-level HFS function PBHGetVolParms returns information in the volume attributes buffer, defined by the GetVolParmsInfoBuffer data type:TYPE GetVolParmsInfoBuffer =RECORD                vMVersion:                        Integer;                {version number}                vMAttrib:                        LongInt;                {volume attributes}                vMLocalHand:                        Handle;                {reserved}                vMServerAdr:                        LongInt;                {network server address}                vMVolumeGrade:                        LongInt;                {relative speed rating}                vMForeignPrivID:                        Integer;                {foreign privilege model}END;vMVersion    The version of the attributes buffer structure. The current version number is 02.vMAttrib    A 32-bit quantity that encodes information about the volume attributes. See the list of constants in the description of PBHGetVolParms for details on the meaning of each bit.vMLocalHand    A handle to private data for shared volumes. On creation of the VCB (right after mounting), this field will be a handle to a 2-byte block of memory. The Finder uses this for its local window list storage, allocating and deallocating memory as needed. It is disposed of when the volume is unmounted. Your application should treat this field as reserved.vMServerAdr    For AppleTalk server volumes, this field contains the internet address of an AppleTalk server volume. Your application can inspect this field to tell which volumes belong to which server; this field is 0 if the volume does not have a server.vMVolumeGrade    The relative speed rating of the volume. The scale used to determine these values is currently uncalibrated. In general, lower values indicate faster speeds. A value of 0 indicates that the volume’s speed is unrated.vMForeignPrivID    An integer representing the privilege model supported by the volume. Currently two values are defined for this field: 0 represents a standard HFS volume that might or might not support the AFP privilege model; fsUnixPriv represents a volume that supports the A/UX privilege model.Volume Mounting Information RecordsThe File Manager remote mounting functions store the mounting information in a variable-sized structure called a volume mounting information record, defined by the VolMountInfoHeader data type.TYPE VolMountInfoHeader =                                                         {volume mounting information}RECORD                length:                        Integer;                {length of mounting information}                media:                        VolumeType;                {type of volume}                {volume-specific, variable-length location data}END;length    The length of the VolMountInfoHeader structure (that is, the total length of the structure header described here plus the variable-length location data). The length of the record is flexible so that non-Macintosh file systems can store whatever information they need for volume mounting.media    The volume type of the remote volume. The value AppleShareMediaType (a constant that translates to 'afpm') represents an AppleShare volume. If you are adding support for the programmatic mounting functions to a non-Macintosh file system, you should register a four-character identifier for your volumes with Macintosh Developer Technical Support at Apple Computer, Inc.The only volumes that currently support the programmatic mounting functions are AppleShare servers, which use a volume mounting record of type AFPVolMountInfo.TYPE AFPVolMountInfo                                =                         {AFP volume mounting information}RECORD                length:                        Integer;                {length of mounting information}                media:                        VolumeType;                {type of volume}                flags:                        Integer;                {reserved; must be set to 0}                nbpInterval:                        SignedByte;                {NBP retry interval}                nbpCount:                        SignedByte;                {NBP retry count}                uamType:                        Integer;                {user authentication method}                zoneNameOffset:                        Integer;                {offset to zone name}                serverNameOffset:                        Integer;                {offset server name}                    volNameOffset:                        Integer;                {offset to volume name}                userNameOffset:                        Integer;                {offset to user name}                userPasswordOffset:                                        Integer;                {offset to user password}                volPasswordOffset:    Integer;                                    {offset to volume password}                AFPData:                        PACKED ARRAY[1..144] OF CHAR;                                                        {standard AFP mounting info}                {optional volume-specific, variable-length data}END;length    The length of the AFPVolMountInfo structure (that is, the total length of the structure header described here plus the variable-length location data).media    The volume type of the remote volume. The value AppleShareMediaType (a constant that translates to 'afpm') represents an AppleShare volume.nbpInterval    The NBP retransmit interval, in units of 8 ticks.npbCount    The NBP retransmit count. This field specifies the total number of times a packet should be transmitted, including the first transmission.uamType    The access-control method used by the remote volume. AppleShare uses four methods, defined by constants:                                CONST                                    kNoUserAuthentication                                = 1;    {no password}                                    kPassword                                = 2;    {8-byte password}                                    kEncryptPassword                                = 3;                                                                {encrypted 8-byte password}                                    kTwoWayEncryptPassword                                = 6;                                                                {two-way random encryption}zoneNameOffset    The offset in bytes from the beginning of the record to the entry in the AFPData field containing the name of the AppleShare zone.serverNameOffset    The offset in bytes from the beginning of the record to the entry in the AFPData field containing the name of the AppleShare server.volNameOffset    The offset in bytes from the beginning of the record to the entry in the AFPData field containing the name of the volume.userNameOffset    The offset in bytes from the beginning of the record to the entry in the AFPData field containing the name of the user.userPasswordOffset    The offset in bytes from the beginning of the record to the entry in the AFPData field containing the user’s password.volPasswordOffset    The offset in bytes from the beginning of the record to the entry in the AFPData field containing the volume’s password.AFPData    The actual volume mounting information, offsets to which are contained in the preceding six fields. To mount an AFP volume, you must fill in the record with at least the zone name, server name, user name, user password, and volume password. You can lay out the data in any order within this data field, as long as you specify the correct offsets in the offset fields.High-Level File Access RoutinesThis section describes the File Manager’s high-level file access routines. When you call one of these routines, you specify a file by a file reference number (which the File Manager returns to your application when the application opens a file). Unless your application has very specialized needs, you should be able to manage all file access (for example, writing data to the file) using the routines described in this section. Typically you use these routines to operate on a file’s data fork, but in certain circumstances you might want to use them on a file’s resource fork as well.Reading, Writing, and Closing FilesYou can use the functions FSRead, FSWrite, and FSClose to read data from a file, write data to a file, and close an open file. All three of these functions operate on open files. You can use any one of a variety of routines to open a file (for example, FSpOpenDF).2FSReadYou can use the FSRead function to read any number of bytes from an open file.FUNCTION FSRead (refNum: Integer; VAR count: LongInt;                         buffPtr: Ptr): OSErr;refNum    The file reference number of an open file.count    On input, the number of bytes to read; on output, the number of bytes actually read.buffPtr    A pointer to the data buffer into which the bytes are to be read.DESCRIPTIONFSRead attempts to read the requested number of bytes from the specified file into the specified buffer. The buffPtr parameter points to that buffer; this buffer is allocated by your application and must be at least as large as the count parameter.The read operation begins at the current mark, so you might want to set the mark first with the SetFPos function. If you try to read past the logical end-of-file, FSRead reads in all the data up to the end-of-file, moves the mark to the end-of-file, and returns eofErr as its function result.The low-level PBRead function lets you set the mark without having to call SetFPos. Also, if you want to read data in newline mode, you must use PBRead instead of FSRead.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openeofErr    –39    End-of-filerfNumErr    –51    Bad reference number2FSWriteYou can use the FSWrite function to write any number of bytes to an open file.FUNCTION FSWrite (refNum: Integer; VAR count: LongInt;                         buffPtr: Ptr): OSErr;refNum    The file reference number of an open file.count    On input, the number of bytes to write to the file; on output, the number of bytes actually written.buffPtr    A pointer to the data buffer from which the bytes are to be written.DESCRIPTIONFSWrite takes the specified number of bytes from the specified data buffer and attempts to write them to the specified file. The write operation begins at the current mark, so you might want to set the mark first with the SetFPos function.The low-level PBWrite function lets you set the mark without having to call SetFPos.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openwPrErr     –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr     –46    Software volume lockrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writing2FSCloseYou can use the FSClose function to close an open file.FUNCTION FSClose (refNum: Integer): OSErr;refNum    The file reference number of an open file.DESCRIPTIONFSClose removes the access path for the specified file and writes the contents of the volume buffer to the volume.FSClose calls PBFlushFile internally to write the file’s bytes onto the volume. To ensure that the file’s catalog entry is updated, you should call FlushVol after you call FSClose.<36pt\>\x12 <8bat\>uMake sure that you do not call FSClose with a file reference number of a file that has already been closed. Attempting to close the same file twice may result in loss of data on a volume. See “File Control Blocks” earlier in this chapter for a description of how this can happen.<36pt\>\x12 <8bat\>sRESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openfnfErr    –43    File not foundrfNumErr    –51    Bad reference numberManipulating the File MarkYou can use the functions GetFPos and SetFPos to get or set the current position of the file mark.2GetFPosYou can use the GetFPos function to determine the current position of the mark before reading from or writing to an open file.FUNCTION GetFPos (refNum: Integer; VAR filePos: LongInt): OSErr;refNum    The file reference number of an open file.filePos    On output, the current position of the mark.DESCRIPTIONGetFPos returns, in the filePos parameter, the current position of the file mark for the specified open file. The position value is 0-based, so that the value of filePos for a file whose mark is positioned at the beginning of the file is 0.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openrfNumErr    –51    Bad reference numbergfpErr    –52    Error during GetFPos2SetFPosYou can use the SetFPos function to set the position of the file mark before reading from or writing to an open file.FUNCTION SetFPos (refNum: Integer; posMode: Integer;                         posOff: LongInt): OSErr;refNum    The file reference number of an open file.posMode    The positioning mode.posOff    The positioning offset.DESCRIPTIONSetFPos sets the file mark of the specified file. The posMode parameter indicates how to position the mark; it must contain one of the following values:CONST                    fsAtMark                = 0;        {at current mark}                    fsFromStart                = 1;        {set mark relative to beginning of file}                    fsFromLEOF                = 2;        {set mark relative to logical end-of-file}                    fsFromMark                = 3;        {set mark relative to current mark}If you specify fsAtMark, the mark is left wherever it’s currently positioned and the posOff parameter is ignored. The other three constants let you position the mark relative to either the beginning of the file, the logical end-of-file, or the current mark. If you specify one of these three constants, you must also pass in posOff a byte offset (either positive or negative) from the specified point. If you specify fsFromLEOF, the value in posOff must be less than or equal to 0.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openeofErr    –39    End-of-fileposErr    –40    Attempt to position before start of filerfNumErr    –51    Bad reference numberManipulating the End-of-FileYou can use the functions GetEOF and SetEOF to get or set the logical end-of-file of an open file.2GetEOFYou can use the GetEOF function to determine the current logical end-of-file of an open file.FUNCTION GetEOF (refNum: Integer; VAR logEOF: LongInt): OSErr;refNum    The file reference number of an open file.logEOF    On output, the logical end-of-file.DESCRIPTIONGetEOF returns, in the logEOF parameter, the logical end-of-file of the specified file. RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openrfNumErr    –51    Bad reference number2SetEOFYou can use the SetEOF function to set the logical end-of-file of an open file.FUNCTION SetEOF (refNum: Integer; logEOF: LongInt): OSErr;refNum    The file reference number of an open file.logEOF    The logical end-of-file.DESCRIPTIONSetEOF sets the logical end-of-file of the specified file. If you attempt to set the logical end-of-file beyond the physical end-of-file, the physical end-of-file is set to one byte beyond the end of the next free allocation block; if there isn’t enough space on the volume, no change is made, and SetEOF returns dskFulErr as its function result.If the logEOF parameter is 0, all space occupied by the file on the volume is released. The file still exists, but is contains 0 bytes. Setting a file fork’s end-of-file to 0 is therefore not the same as deleting the file (which removes both file forks at once).RESULT CODESnoErr    0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writingAllocating File BlocksThe File Manager provides two functions, Allocate and AllocContig, that allow you to allocate additional blocks to a file. The File Manager automatically allocates file blocks if you move the logical end-of-file past the physical end-of-file, and it automatically deallocates unneeded blocks from a file if you move the logical end-of-file to a position more than one allocation block short of the current physical end-of-file. Consequently, you do not in general need to be concerned with allocating or deallocating file blocks. However, you can improve file block contiguity if you preallocate file blocks using the Allocate or AllocContig function. This is most useful if you know in advance how big a file is likely to become.When the File Manager allocates (or deallocates) file blocks automatically, it always adds (or removes) blocks in clumps. The Allocate and AllocContig functions allow you to add blocks in allocation blocks, which may be smaller than clumps.<36pt\>\x12 <8bat\>u2AllocateYou can use the Allocate function to allocate additional blocks to an open file.FUNCTION Allocate (refNum: Integer; VAR count: LongInt): OSErr;refNum    The file reference number of an open file.count    On input, the number of additional bytes to allocate to the file; on output, the number of bytes actually allocated, rounded up to the nearest multiple of the allocation block size.DESCRIPTIONAllocate adds the specified number of bytes to the specified file and sets the physical end-of-file to one byte beyond the last block allocated. If there isn’t enough empty space on the volume to satisfy the allocation request, Allocate allocates the rest of the space on the volume and returns dskFulErr as its function result.Allocate always attempts to allocate contiguous blocks. If the total number of requested bytes is unavailable, Allocate will allocate whatever space, contiguous or not, is available. To force the allocation of the entire requested space as a contiguous piece, call AllocContig instead.RESULT CODESnoErr     0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writing2AllocContigYou can use the AllocContig function to allocate additional contiguous blocks to an open file.FUNCTION AllocContig (refNum: Integer; VAR count: LongInt): OSErr;refNum    The file reference number of an open file.count    On input, the number of additional bytes to allocate to the file; on output, the number of bytes allocated, rounded up to the nearest multiple of the allocation block size.DESCRIPTIONAllocContig is identical to the Allocate function except that if there isn’t enough contiguous empty space on the volume to satisfy the allocation request, AllocContig does nothing and returns dskFulErr as its function result. If you want to allocate whatever space is available, even when the entire request cannot be filled as a contiguous piece, call Allocate instead.RESULT CODESnoErr     0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writingLow-Level File Access RoutinesThis section describes the low-level file access routines. These low-level routines, whose names begin with the letters “PB,” provide two advantages over the corresponding high-level file access routines:n    These routines can be executed asynchronously, returning control to your application without waiting for the operation to complete.n    In certain cases, these routines provide more extensive information or perform advanced operations.All of these routines exchange parameters with your application through a parameter block of type ParamBlock. When you call a low-level routine, you pass the address of the parameter block to the routine.These low-level file access routines can run either synchronously or asynchronously. There are three versions of each routine. The first takes two parameters: a pointer to the parameter block and a Boolean parameter that specifies whether the routine is to run asynchronously (TRUE) or synchronously (FALSE). For example, the first version of the low-level routine to read bytes from a file has this declaration:FUNCTION PBRead (paramBlock: ParmBlkPtr; async: Boolean): OSErr;The second version does not take a second parameter; instead, it adds the suffix “Async” to the name of the routine.FUNCTION PBReadAsync (paramBlock: ParmBlkPtr): OSErr;Similarly, the third version of the routine does not take a second parameter; instead, it adds the suffix “Sync” to the name of the routine.FUNCTION PBReadSync (paramBlock: ParmBlkPtr): OSErr;Only the first version of each routine is documented in this section. (See the Summary section at the end of this chapter for a listing of all three versions of these routines.) Note however that the second and third versions of these routines do not use the glue code that the first version uses and are therefore more efficient.Although you can execute low-level file access routines asynchronously, the underlying device driver may not support asynchronous operation. The SCSI Manager, for example, currently supports only synchronous data transfers. Data transfers to a floppy disk or to a network server, however, can be made asynchronously. <36pt\>\x12 <8bat\>uReading, Writing, and Closing FilesYou can use the functions PBRead, PBWrite, and PBClose to read data from a file, write data to a file, and close an open file. All three of these functions operate on open files. You can use any one of a variety of routines to open a file (for example, PBHOpenDF).2PBReadYou can use the PBRead function to read any number of bytes from an open file.FUNCTION PBRead (paramBlock: ParmBlkPtr; async: Boolean): OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.Æ     ioBuffer    Ptr    A pointer to a data buffer.Æ     ioReqCount    LongInt    The number of bytes requested.¨     ioActCount    LongInt    The number of bytes actually read.Æ     ioPosMode    Integer    The positioning mode.´     ioPosOffset    LongInt    The positioning offset.DESCRIPTIONPBRead attempts to read ioReqCount bytes from the open file whose access path is specified in the ioRefNum field and transfer them to the data buffer pointed to by the ioBuffer field. The position of the mark is specified by ioPosMode and ioPosOffset. If your application tries to read past the logical end-of-file, PBRead reads the data, moves the mark to the end-of-file, and returns eofErr as its function result. After the read is completed, the mark is returned in ioPosOffset and the number of bytes actually read into the buffer is returned in ioActCount.You can specify that PBRead read the file data one byte at a time until the requested number of bytes have been read or until the end-of-file is reached by setting bit 7 of the ioPosMode field. Similarly, you can specify that PBRead should stop reading data when it reaches an application-defined newline character by placing the ASCII code of that character into the high-order byte of the ioPosMode field; you must also set bit 7 of that field to enable newline mode. When reading data in newline mode, PBRead returns the newline character as part of the data read and sets ioActCount to the actual number of bytes placed into the buffer (which includes the newline character).<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openeofErr    –39    End-of-fileposErr     –40    Attempt to position before start of filefLckdErr    -45    File lockedparamErr    –50    Negative ioReqCountrfNumErr    –51    Bad reference number2PBWriteYou can use the PBWrite function to write any number of bytes to an open file.FUNCTION PBWrite (paramBlock: ParmBlkPtr; async: Boolean): OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.Æ     ioBuffer    Ptr    A pointer to a data buffer.Æ     ioReqCount    LongInt    The number of bytes requested.¨     ioActCount    LongInt    The number of bytes actually written.Æ     ioPosMode    Integer    The positioning mode.´     ioPosOffset    LongInt    The positioning offset.DESCRIPTIONPBWrite takes ioReqCount bytes from the buffer pointed to by ioBuffer and attempts to write them to the open file whose access path is specified by ioRefNum. The position of the mark is specified by ioPosMode and ioPosOffset. After the write is completed, the mark is returned in ioPosOffset and the number of bytes actually written is returned in ioActCount.RESULT CODESnoErr    0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openposErr     –40    Attempt to position before start of filewPrErr     –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr     –46    Software volume lockparamErr    –50    Negative ioReqCountrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writing2PBCloseYou can use the PBClose function to close an open file.FUNCTION PBClose (paramBlock: ParmBlkPtr; async: Boolean): OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.DESCRIPTIONPBClose writes the contents of the access path buffer specified by the ioRefNum field to the volume and removes the access path.Some information stored on the volume won’t be updated until PBFlushVol is called.<36pt\>\x12 <8bat\>s Do not call PBClose with a file reference number of a file that has already been closed. Attempting to close the same file twice may result in loss of data on a volume. See “File Control Blocks” earlier in this chapter for a description of how this can happen.<36pt\>\x12 <8bat\>sRESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openfnfErr    –43    File not foundrfNumErr    –51    Bad reference numberManipulating the File MarkYou can use the functions PBGetFPos and PBSetFPos to get or set the current position of the file mark.2PBGetFPosYou can use the PBGetFPos function to determine the current position of the file mark before reading from or writing to an open file.FUNCTION PBGetFPos (paramBlock: ParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum     Integer    A file reference number.¨     ioReqCount     LongInt    On output, set to 0.¨     ioActCount    LongInt    On output, set to 0.¨     ioPosMode    Integer    On output, set to 0.¨     ioPosOffset    LongInt    The current position of the mark.DESCRIPTIONPBGetFPos returns, in the ioPosOffset field, the mark of the specified file. The value returned in ioPosOffset is 0-based, so that a call to PBGetFPos on a file whose file mark is positioned at the beginning of the file would return 0.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openrfNumErr    –51    Bad reference numbergfpErr    –52    Error during PBGetFPos2PBSetFPosYou can use the PBSetFPos function to position the file mark before reading from or writing to an open file.FUNCTION PBSetFPos (paramBlock: ParmBlkPtr; async: Boolean):                            OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.Æ     ioPosMode    Integer    The positioning mode.´     ioPosOffset    LongInt    On input, the positioning offset. On output, the position at which the mark was actually set.DECRIPTIONPBSetFPos sets the mark of the specified file to the position specified by the ioPosMode and ioPosOffset fields. If you try to set the mark past the logical end-of-file, PBSetFPos moves the mark to the end-of-file and returns eofErr as its function result.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openeofErr    –39    End-of-fileposErr    –40    Attempt to position before start of filerfNumErr    –51    Bad reference numberextFSErr    –58    External file systemManipulating the End-of-FileYou can use the functions PBGetEOF and PBSetEOF to get or set the current end-of-file.2PBGetEOFYou can use the PBGetEOF function to determine the current logical end-of-file of an open file.FUNCTION PBGetEOF (paramBlock: ParmBlkPtr; async: Boolean): OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.¨     ioMisc    Ptr    The logical end-of-file.DESCRIPTIONPBGetEOF returns, in the ioMisc field, the logical end-of-file of the specified file. Because ioMisc is of type Ptr, you’ll need to perform type coercion to a LongInt to interpret the value correctly.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openrfNumErr    –51    Bad reference number2PBSetEOFYou can use the PBSetEOF function to set the logical end-of-file of an open file.FUNCTION PBSetEOF (paramBlock: ParmBlkPtr; async: Boolean): OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.Æ     ioMisc    Ptr    The logical end-of-file.DESCRIPTIONPBSetEOF sets the logical end-of-file of the open file, whose access path is specified by ioRefNum, to ioMisc. Because the ioMisc field is of type Ptr, you must coerce the desired value from a LongInt to a Ptr.If you attempt to set the logical end-of-file beyond the current physical end-of-file, another allocation block is added to the file; if there isn’t enough space on the volume, no change is made and PBSetEOF returns dskFulErr as its function result.If the ioMisc field is 0, all space occupied by the file on the volume is released. The file still exists, but is contains 0 bytes. Setting a file fork’s end-of-file to 0 is therefore not the same as deleting the file (which removes both file forks at once).RESULT CODESnoErr    0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writingAllocating File BlocksThe File Manager provides two low-level functions, PBAllocate and PBAllocContig, that allow you to allocate additional blocks to a file. The File Manager automatically allocates file blocks if you move the logical end-of-file past the physical end-of-file, and it automatically deallocates unneeded blocks from a file if you move the logical end-of-file to a position more than one allocation block short of the current physical end-of-file. Consequently, you do not in general need to be concerned with allocating or deallocating file blocks. However, you can improve file block contiguity if you preallocate file blocks using the PBAllocate or PBAllocContig function. This is most useful if you know in advance how big a file is likely to become.2PBAllocateYou can use the PBAllocate function to allocate additional blocks to an open file.FUNCTION PBAllocate (paramBlock: ParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.Æ     ioReqCount    LongInt    The number of bytes requested.¨     ioActCount    LongInt    The number of bytes actually allocated, rounded up to the nearest multiple of the allocation block size.DESCRIPTIONPBAllocate adds ioReqCount bytes to the specified file and sets the physical end-of-file to one byte beyond the last block allocated. If there isn’t enough empty space on the volume to satisfy the allocation request, PBAllocate allocates the rest of the space on the volume and returns dskFulErr as its function result.If the total number of requested bytes is unavailable, PBAllocate will allocate whatever space, contiguous or not, is available. To force the allocation of the entire requested space as a contiguous piece, call PBAllocContig instead.<36pt\>\x12 <8bat\>uRESULT CODESnoErr     0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writing2PBAllocContigYou can use the PBAllocContig function to allocate additional contiguous blocks to an open file.FUNCTION PBAllocContig (paramBlock: ParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.Æ     ioReqCount    LongInt    The number of bytes requested.¨     ioActCount    LongInt    The number of bytes allocated, rounded up to the nearest multiple of the allocation block size.DESCRIPTIONPBAllocContig is identical to the PBAllocate function except that if there isn’t enough contiguous empty space on the volume to satisfy the allocation request, PBAllocContig does nothing and returns dskFulErr as its function result. If you want to allocate whatever space is available, even when the entire request cannot be filled as a contiguous piece, call PBAllocate instead.RESULT CODESnoErr    0    No errordskFulErr    –34    Disk fullioErr    –36    I/O errorfnOpnErr    –38    File not openwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockrfNumErr    –51    Bad reference numberwrPermErr    –61    Read/write permission doesn’t allow writingUpdating FilesYou can use the PBFlushFile function to ensure that the path access buffer of a file is written out to disk. There is no high-level equivalent of this function.2PBFlushFileYou can use the PBFlushFile function to write the contents of a file’s access path buffer.FUNCTION PBFlushFile (paramBlock: ParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.DESCRIPTIONPBFlushFile writes the contents of the access path buffer indicated by ioRefNum to the volume, and updates the file’s entry in the volume catalog.Some information stored on the volume won’t be correct until PBFlushVol is called.<36pt\>\x12 <8bat\>sRESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr     –36    I/O errorfnOpnErr     –38    File not openfnfErr    –43    File not foundrfNumErr    –51    Bad reference numberextFSErr    –58    External file systemHigh-Level Volume Access RoutinesThis section describes the File Manager’s high-level volume access routines.  Most applications are likely to need only the FlushVol function described in “Updating Volumes.”When you call one of these routines, you specify a volume by a volume reference number (which you can obtain, for example, by calling the GetVInfo function, or from the reply record returned by the Standard File Package). You can also specify a volume by name, but this is generally discouraged, because there is no guarantee that volume names will be unique.Unmounting VolumesThe functions UnmountVol and Eject allow you to unmount and eject volumes. Most applications do not need to use these routines, because the user typically ejects (and possibly also unmounts) a volume in the Finder.2UnmountVolYou can use the UnmountVol function to unmount a volume that isn’t currently being used.FUNCTION UnmountVol (volName: StringPtr; vRefNum: Integer): OSErr;volName    A pointer to the name of a mounted volume.vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.DESCRIPTIONUnmountVol unmounts the specified volume. All files on the volume (except those opened by the Operating System) must be closed before you call UnmountVol.Don’t unmount the startup volume.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad volume namefBsyErr    –47    One or more files are openparamErr    –50    No default volumensDrvErr    –56    No such driveextFSErr    –58    External file system2EjectYou can use the Eject function to place a volume off-line and eject it.FUNCTION Eject (volName: StringPtr; vRefNum: Integer): OSErr;volName    A pointer to the name of a volume.vRefNum    A volume reference number, a working directory reference number, a drive number, or 0 for the default volume.DESCRIPTIONEject flushes the specified volume, places it off-line, and then ejects the volume.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad volume nameparamErr    –50    No default volumensDrvErr    –56    No such driveextFSErr    –58    External file systemUpdating VolumesWhen you close a file, you should call FlushVol to ensure that any changed contents of the file are written to the volume.2FlushVolYou can use the FlushVol function to write out the contents of the volume buffer and update information about the volume.FUNCTION FlushVol (volName: StringPtr; vRefNum: Integer): OSErr;volName    A pointer to the name of a mounted volume.vRefNum    A volume reference number, a working directory reference number, a drive number, or 0 for the default volume.DESCRIPTIONOn the specified volume, the FlushVol function writes the contents of the associated volume buffer and descriptive information about the volume (if they’ve changed since the last time FlushVol was called) to the volume.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad volume nameparamErr    –50    No default volumensDrvErr    –56    No such driveManipulating the Default VolumeThe functions GetVol, SetVol, HGetVol and HSetVol allow you to determine which volume is the default volume and to set the default volume.2GetVolYou can use the GetVol function to determine the current default volume and possibly also the default directory.FUNCTION GetVol (volName: StringPtr; VAR vRefNum: Integer): OSErr;volName    A pointer to the name of the default volume.vRefNum    A volume reference number or a working directory reference number.DESCRIPTIONGetVol returns a pointer to the name of the default volume in the volName parameter and its volume reference number in the vRefNum parameter. If the default directory has a working directory associated with it, the vRefNum parameter instead contains a working directory reference number (which encodes both the volume reference number and the default directory ID). However, if, in a previous call to HSetVol (or PBHSetVol), a working directory reference number was passed in, GetVol returns a volume reference number in the vRefNum parameter.RESULT CODESnoErr    0    No errornsvErr    –35    No such volume2SetVolYou can change the default volume and default directory using the SetVol function.FUNCTION SetVol (volName: StringPtr; vRefNum: Integer): OSErr;volName    A pointer to the name of a mounted volume.vRefNum    A volume reference number or a working directory reference number.DESCRIPTIONSetVol sets the default volume and directory to the values specified in the volName and vRefNum parameters. If you pass a volume reference number in vRefNum or a pointer to a volume name in volName, SetVol makes the specified volume the default volume and the root directory of that volume the default directory. If you pass a working directory reference number in vRefNum, SetVol makes the specified directory the default directory, and the volume containing that directory the default volume.RESULT CODESnoErr    0    No errorbdNamErr    –37    Bad volume namensvErr    –35    No such volumeparamErr    –50    No default volume2HGetVolYou can use the HGetVol function to determine the current default volume and default directory.FUNCTION HGetVol (volName: StringPtr; VAR vRefNum: Integer;                         VAR dirID: LongInt): OSErr;volName    A pointer to the name of the default volume.vRefNum    A volume reference number or a working directory reference number.dirID    The directory ID of the default directory.DESCRIPTIONThe HGetVol function returns the name and reference number of the default volume, as well as the directory ID of the default directory. A pointer to the name of the default volume is returned in the volName parameter, unless you set volName to NIL before calling HGetVol.HGetVol returns a working directory reference number in the vRefNum parameter if the previous call to HSetVol (or PBHSetVol) passed in a working directory reference number. If, however, you have previously called HSetVol (or PBHSetVol) specifying the target volume with a volume reference number, then HGetVol returns a volume reference number in the vRefNum parameter.RESULT CODESnoErr    0    No errornsvErr    –35    No default volume2HSetVolYou can use the HSetVol function to set both the default volume and the default directory.FUNCTION HSetVol (volName: StringPtr; vRefNum: Integer;                         dirID: LongInt): OSErr;volName    A pointer to the name of a mounted volume or the partial pathname of a directory.vRefNum    A volume reference number or a working directory reference number.dirID    A directory ID.DESCRIPTIONHSetVol lets you specify the default directory by volume reference number, directory ID, or by a combination of working directory reference number and partial pathname (beginning from that working directory).Use of the PBHSetVol function is discouraged if your application may execute in system software versions prior to version 7.0. Because the specified directory might not itself be a working directory, HSetVol records the default volume and directory separately, using the volume reference number of the volume and the actual directory ID of the specified directory. Subsequent calls to GetVol (or PBGetVol) return only the volume reference number, which will cause that volume’s root directory to be accessed (rather than the default directory, as expected).<36pt\>\x12 <8bat\>s Both the default volume and the default directory are used in calls made with no volume name and a volume reference number of zero.<36pt\>\x12 <8bat\>u RESULT CODESnoErr    0    No errornsvErr    –35    No such volumebdNamErr    –37    Bad volume namefnfErr    –43    Directory not foundparamErr    –50    No default volumeObtaining Volume InformationYou can get information about a volume by calling the GetVInfo or GetVRefNum functions.2GetVInfoYou can use the GetVInfo function to get information about a mounted volume.FUNCTION GetVInfo (drvNum: Integer; volName: StringPtr;                             VAR vRefNum: Integer;                             VAR freeBytes: LongInt): OSErr;drvNum    The drive number of the volume for which information is requested.volName    On output, a pointer to the name of the specified volume.vRefNum    The volume reference number of the specified volume. freeBytes    The available space (in bytes) on the specified volume.DESCRIPTIONGetVInfo returns the name, volume reference number, and available space (in bytes) for the specified volume. You specify a volume by providing its drive number in the drvNum parameter. You can pass 0 in the drvNum parameter to get information about the default volume.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeparamErr    –50    No default volume2GetVRefNumYou can use the GetVRefNum function to get a volume reference number from a file reference number.FUNCTION GetVRefNum (refNum: Integer; VAR vRefNum: Integer):                             OSErr;refNum    The file reference number of an open file.vRefNum    The volume reference number of the volume.DESCRIPTIONGetVRefNum returns the volume reference number of the volume containing the specified file.RESULT CODESnoErr    0    No errorrfNumErr    –51    Bad reference numberLow-Level Volume Access RoutinesThis section describes the low-level volume access routines. These routines exchange parameters with your application through a parameter block of type ParamBlock, HParamBlock, or WDPBRec. When you call a low-level routine, you pass the address of the appropriate parameter block to the routine.Some low-level volume access routines can run either asynchronously or synchronously. Each of these routines comes in three versions: one version requires the asynch parameter and two have the suffix “Asynch” or “Sync” added to their names. For more information about the diffrences between the three versions, see “Low-Level File Access Routines” earlier in this chapter.Only the first version of these routines is documented in this section. See the Summary at the end of this chapter for a listing that includes all three versions.Mounting and Unmounting VolumesThe File Manager provides several low-level routines that allow you to mount and unmount Macintosh volumes, eject volumes, and to place mounted volumes off-line.2PBMountVolYou can use the PBMountVol function to mount a volume.FUNCTION PBMountVol (paramBlock: ParmBlkPtr): OSErr;paramBlock    A pointer to a basic parameter block.¨     ioResult    OSErr    The result code of the function.´     ioVRefNum    Integer    On input, a drive number. On output, the volume reference number.DESCRIPTIONPBMountVol mounts the volume in the specified drive. If there are no volumes already mounted, this volume becomes the default volume.Because you specify the volume to be mounted by providing a drive number, you can use PBMountVol to mount only one volume per disk.PBMountVol always executes synchronously.PBMountVol opens two files needed for maintaining file catalog and file mapping information. If there are no access paths available for these two files, PBMountVol will fail and return tmfoErr as its function result.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errorioErr    –36    I/O errortmfoErr    –42    Too many files openparamErr    –50    Bad drive numbervolOnLinErr    –55    Volume already onlinensDrvErr    –56    No such drivenoMacDskErr    –57    Not a Macintosh diskextFSErr    –58    External file systembadMDBErr    –60    Bad master directory blockmemFullErr    –108    Not enough room in heap zone2PBUnmountVolYou can use the PBUnmountVol function to unmount a volume.FUNCTION PBUnmountVol (paramBlock: ParmBlkPtr): OSErr;paramBlock    A pointer to a basic parameter block.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume reference number, a working directory reference number, or 0 for the default volume.DESCRIPTIONPBUnmountVol unmounts the specified volume. All user files on the volume must be closed. PBUmountVol calls PBFlushVol to flush the volume and releases the memory used for the volume.PBUnmountVol always executes synchronously.Don’t unmount the startup volume. Unmounting a volume does not close working directories; to release the memory allocated to a working directory, call PBCloseWD.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad volume namefBsyErr    –47    One or more files are openparamErr    –50    No default volumensDrvErr    –56    No such driveextFSErr    –58    External file system2PBEjectWhen your application is finished with a volume, you can use the PBEject function to place the volume off-line and eject it.FUNCTION PBEject (paramBlock: ParmBlkPtr): OSErr;paramBlock    A pointer to a basic parameter block.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.DESCRIPTIONPBEject flushes the specified volume, places it off-line, and then ejects the volume.ASSEMBLY LANGUAGE INFORMATIONYou can invoke the macro _Eject asynchronously; the first two parts of the call are executed synchronously, and the actual ejection is executed asynchronously.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad volume nameparamErr    –50    No default volumensDrvErr    –56    No such driveextFSErr    –58    External file system2PBOfflineYou can use the PBOffline function to place a volume offline. Most applications do not need to do this.FUNCTION PBOffLine (paramBlock: ParmBlkPtr): OSErr;paramBlock    A pointer to a basic parameter block.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.DESCRIPTIONPBOffLine places the specified volume off-line by calling PBFlushVol to flush the volume and releasing all the memory used for the volume except for the volume control block.PBOffLine always executes synchronously.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad volume nameparamErr    –50    No default volumensDrvErr    –56    No such driveextFSErr    –58    External file systemUpdating VolumesYou can update a volume by calling PBFlushVol.2PBFlushVolYou can use the PBFlushVol function to write out the contents of the volume buffer and update information about the volume.FUNCTION PBFlushVol (paramBlock: ParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.DESCRIPTIONOn the volume specified by ioNamePtr or ioVRefNum, PBFlushVol writes descriptive information about the volume, the contents of the associated volume buffer, and all access path buffers for the volume (if they’ve changed since the last time PBFlushVol was called).The date and time of the last modification to the volume are set when the modification is made, not when the volume is flushed.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad volume nameparamErr    –50    No default volumensDrvErr    –56    No such driveextFSErr    –58    External file systemObtaining Volume InformationThe File Manager provides several routines that allow you to obtain and modify information about a volume. For example, you can use the PBHGetVInfo function to determine the date and time that a volume was last modified. You can use the PBHGetVolParms function to determine other features of the volume, such as whether it supports the PBHOpenDeny routine.2PBHGetVInfoYou can use the PBHGetVInfo function to get detailed information about a volume.FUNCTION PBHGetVInfo (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.´     ioNamePtr    StringPtr    A pointer to the volume’s name.´     ioVRefNum    Integer    On input, a volume specification. On output, the volume reference number.Æ     ioVolIndex    Integer    An index used for indexing through all mounted volumes.¨     ioVCrDate    LongInt    The date and time of initialization.¨     ioVLsMod    LongInt    The date and time of last modification.¨     ioVAtrb    Integer    The volume attributes.¨     ioVNmFls    Integer    The number of files in the root directory.¨     ioVBitMap    Integer    The first block of the volume bitmap.¨     ioVAllocPtr    Integer    The block at which the next new file starts.¨     ioVNmAlBlks    Integer    The number of allocations blocks.¨     ioVAlBlkSiz    LongInt    The size of allocation blocks.¨     ioVClpSiz    LongInt    The number of bytes to allocate.¨     ioAlBlSt    Integer    The first block in the volume block map.¨     ioVNxtCNID    LongInt    The next unused catalog node ID.¨     ioVFrBlk    Integer    The number of unused allocation blocks.¨     ioVSigWord    Integer    The volume signature.¨     ioVDrvInfo    Integer    The drive number.¨     ioVDRefNum    Integer    The driver reference number.¨     ioVFSID    Integer    The file system handling this volume.¨     ioVBkUp    LongInt    The date and time of the last backup.¨     ioVSeqNum    Integer    Used internally.¨     ioVWrCnt    LongInt    The volume write count.¨     ioVFilCnt    LongInt    The number of files on the volume.¨     ioVDirCnt    LongInt    The number of directories on the volume.¨     ioVFndrInfo    ARRAY[1..8] of LongIntInformation used by the Finder.DESCRIPTIONPBHGetVInfo returns information about the specified volume. If ioVolIndex is positive, the File Manager attempts to use it to find the volume; for instance, if ioVolIndex is 2, the File Manager attempts to access the second mounted volume. If ioVolIndex is negative, the File Manager uses ioNamePtr and ioVRefNum in the standard way to determine which volume. If ioVolIndex is 0, the File Manager attempts to access the volume by using ioVRefNum only. The volume reference number is returned in ioVRefNum, and the volume name is returned in the buffer whose address you passed ioNamePtr (unless ioNamePtr is NIL).If a working directory reference number is passed in ioVRefNum (or if the default directory is a subdirectory), the number of files and directories in the specified directory (the directory’s valence) is returned in ioVNmFls.SPECIAL CONSIDERATIONSThe values returned in the ioVNmAlBlks and ioVFrBlk fields are unsigned integers. You need to exercise special care when reading those values from Pascal. See “Determining the Amount of Free Space on a Volume” on page 2-41 for one technique you can use to read those values.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeparamErr    –50    No default volume2PBSetVInfoYou can use the PBSetVInfo to change information about a volume.FUNCTION PBSetVInfo (paramBlock: HParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to the volume’s name.Æ     ioVRefNum    Integer    A volume specification.Æ     ioVCrDate    LongInt    The date and time of initialization.Æ     ioVLsMod    LongInt    The date and time of last modification.Æ     ioVAtrb    Integer    The volume attributes.Æ     ioVClpSiz    LongInt    The number of bytes to allocate.Æ     ioVBkUp    LongInt    The date and time of the last backup.Æ     ioVSeqNum    Integer    Used internally.Æ     ioVFndrInfo    ARRAY[1..8] of LongIntInformation used by the Finder.DESCRIPTIONPBSetVInfo lets you modify information about volumes. A pointer to a new name for the volume can be specified in ioNamePtr. Only bit 15 of ioVAtrb can be changed; setting it locks the volume.The volume cannot be specified by name; you must use either the volume reference number, the drive number, or a working directory reference number.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errornsvErr    –35    No such volumeparamErr    –50    No default volume2PBHGetVolParmsYou can use the PBHGetVolParms function to determine the characteristics of a volume.FUNCTION PBHGetVolParms (paramBlock: HParmBlkPtr; async: Boolean):                                  OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ    ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to the volume’s name.Æ    ioVRefNum    Integer    A volume specification.Æ     ioBuffer    Ptr    A pointer to a GetVolParmsInfoBuffer record.Æ    ioReqCount    LongInt    The size of the buffer area.¨     ioActCount    LongInt    The size of the data actually returned.DESCRIPTIONThe PBHGetVolParms function returns information about the characteristics of a volume. You specify a volume (by either name or volume reference number) and a buffer size, and PBHGetVolParms fills in the volume-attributes buffer, as described in this section.You can specify the volume to be described with a name (pointed to by the ioNamePtr field) or a volume specification (contained in the ioVRefNum field). A volume specification can be a volume reference number, drive number, or working directory reference number. If you use a volume specification to specify the volume, you should set the ioNamePtr field to NIL.You must allocate memory to hold the returned attributes and put a pointer to the buffer in the ioBuffer field. Specify the size of the buffer in the ioReqCount field. PBHGetVolParms places the attributes information in the buffer pointed to by the ioBuffer field and specifies the actual length of the data in the ioActCount field.PBHGetVolParms returns the bulk of its volume description in the vMAttrib field of the attributes buffer. The vMAttrib field contains 32 bits of attribute information about the volume. Bits 0–3 and 21–24 are reserved; all volumes should return these bits clear. The bits currently used are defined by constants:CONST                bHasBlankAccessPrivileges                                    =    4;        {volume supports inherited folder }                                                { privileges}                bHasBtreeMgr                    =    5;        {reserved}                bHasFileIDs                    =    6;        {volume supports file ID functions}                bHasCatSearch                    =    7;        {volume supports PBCatSearch}                bHasUserGroupList                                                        =    8;        {volume supports AFP privileges}                bHasPersonalAccessPrivileges                                    =    9;        {local file sharing is enabled}                bHasFolderLock                    =    10;        {volume’s root folder is locked}                bHasShortName                    =    11;        {volume supports shorter volume name}                bHasDesktopMgr                    =    12;        {volume supports Desktop Manager}                bHasMoveRename                    =    13;        {volume supports _MoveRename}                bHasCopyFile                    =    14;        {volume supports _CopyFile}                bHasOpenDeny                    =    15;        {volume supports shared access modes}                bHasExtFSVol                    =    16;        {volume is external file system volume}                bNoSysDir                    =    17;        {volume has no system directory}                bAccessCntl                    =    18;        {volume supports AFP access control}                bNoBootBlks                    =    19;        {volume is not a startup volume}                bNoDeskItems                    =    20;        {do not place objects on the desktop}                bNoSwitchTo                    =    25;        {do not switch launch to applications}                bTrshOffLine                    =    26;        {zoom volume when it is unmounted}                bNoLclSync                    =    27;        {don’t let Finder change mod. date}                bNoVNEdit                    =    28;        {lock volume name}                bNoMiniFndr                    =    29;        {reserved; always 1}                bLocalWList                    =    30;        {use shared volume handle for window }                                                { list}                bLimitFCBs                    =    31;        {limit file control blocks}These constants have the following meanings if set:Constant descriptionsbHasBlankAccessPrivileges    This volume supports inherited access privileges for folders.bHasBtreeMgr    Reserved for internal use.bHasFileIDs    This volume supports the file ID functions, including the PBExchangeFiles function.bHasCatSearch    This volume supports the PBCatSearch function.bHasUserGroupListThis volume supports the Users and Groups file and thus the AFP privilege functions.bHasPersonalAccessPrivilegesThis volume has local file sharing enabled.bHasFolderLock    Volume’s root folder is locked.bHasShortName    This volume supports a name that fits the shorter length requirements of another file system.bHasDesktopMgr    This volume supports all of the desktop functions (described in the Finder Interface chapter of the Toolbox volume).bHasMoveRename    This volume supports the MoveRename function.bHasCopyFile    This volume supports the CopyFile function, which is used in copy and duplicate operations if both source and destination volumes have the same server address.bHasOpenDeny    This volume supports the OpenDeny and OpenRFDeny functions. For copy operations, source files are opened with reading enabled and writing denied; destination files are opened with writing enabled and reading and writing denied.bHasExtFSVol    This volume is an external file system volume.bNoSysDir    This volume doesn’t support a system directory. Do not switch launch to this volume.bAccessCntl    This volume supports AppleTalk AFP access-control interfaces. The GetLoginInfo, GetDirAccess, SetDirAccess, MapID, and MapName functions are supported. Special folder icons are used. The Access Privileges menu command is enabled for disk and folder items. The privileges field of GetCatInfo calls is assumed to be valid.bNoBootBlks    This volume is not a startup volume. The Startup menu item is disabled. Boot blocks are not copied during copy operations.bNoDeskItems    Do not place objects in this volume on the Finder desktop.bNoSwitchTo    The Finder will not switch launch to any application on this volume.bTrshOffLine    Any time this volume goes offline, it is zoomed to the Trash and unmounted.bNoLclSync    Do not let the Finder change the modification date.bNoVNEdit    This volume’s name cannot be edited.bNoMiniFndr    Reserved; always set to 1.bLocalWList    Finder uses the returned shared volume handle for its local window list.bLimitFCBs    The Finder limits the number of file control blocks used during copying to 8 instead of 16.SPECIAL CONSIDERATIONSA volume’s characteristics can change when the user enables and disables file sharing. You might have to make repeated calls to PBHGetVolParms to ensure that you have the current status of a volume.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundparamErr    –50    Volume doesn’t support the functionManipulating the Default VolumeThe low-level functions PBGetVol, PBSetVol, PBHGetVol, and PBHSetVol allow you to manipulate the default volume and directory.2PBGetVolYou can use the PBGetVol function to determine the default volume and default directory.FUNCTION PBGetVol (paramBlock: ParmBlkPtr; async: Boolean): OSErr;paramBlock    A pointer to a basic File Manager parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.PARAMETER BLOCKÆ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.¨     ioNamePtr    StringPtr    A pointer to a pathname.¨     ioVRefNum    Integer    A volume reference number or a working directory reference number.DESCRIPTIONPBGetVol returns a pointer to the name of the default volume in ioNamePtr (unless ioNamePtr is NIL) and its volume reference number in ioVRefNum. If a default directory was set with a previous PBSetVol call, a pointer to its name will be returned in ioNamePtr and its working directory reference number in ioVRefNum.  However, if, in a previous call to HSetVol (or PBHSetVol), a working directory reference number was passed in, PBGetVol returns a volume reference number in the ioVRefNum field.RESULT CODESnoErr    0    No errornsvErr    –35    No default volume2PBSetVolYou can change the default volume and default directory using the PBSetVol function.FUNCTION PBSetVol (paramBlock: ParmBlkPtr; async: Boolean): OSErr;paramBlock    A pointer to a basic FIle Manager parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.PARAMETER BLOCKÆ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume reference number or a working directory reference number.DESCRIPTIONIf you pass a volume reference number in ioVRefNum, PBSetVol makes the specified volume the default volume and the root directory of that volume the default directory. If you pass a working directory reference number, PBSetVol makes the specified directory the default directory, and the volume containing that directory the default volume.RESULT CODESnoErr    0    No errorbdNamErr    –37    Bad volume namensvErr    –35    No such volumeparamErr    –50    No default volume2PBHGetVolYou can use the PBHGetVol function to determine the default volume and default directory.FUNCTION PBHGetVol (paramBlock: WDPBPtr; async: Boolean): OSErr;paramBlock    A pointer to a working directory parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult     OSErr    The result code of the function.¨     ioNamePtr    StringPtr    A pointer to a pathname.¨     ioVRefNum    Integer    A volume reference number or a working directory reference number.¨     ioWDProcID    LongInt    The working directory user identifier.¨     ioWDVRefNum    Integer    The volume reference number of the default volume.¨     ioWDDirID    LongInt    The directory ID of the default directory.DESCRIPTIONPBHGetVol returns the default volume and directory last set by either a PBSetVol or a PBHSetVol call. The reference number of the default volume is returned in ioVRefNum.The ioVRefNum field will return a working directory reference number (instead of the volume reference number) if, in the last call to PBSetVol or PBHSetVol, a working directory reference number was passed in this field.<36pt\>\x12 <8bat\>sThe volume reference number of the volume on which the default directory exists is returned in ioWDVRefNum. The directory ID of the default directory is returned in ioWDDirID.RESULT CODESnoErr    0    No errornsvErr    –35    No default volume2PBHSetVolThe PBHSetVol function sets both the default volume and the default directory.FUNCTION PBHSetVol (paramBlock: WDPBPtr; async: Boolean): OSErr;paramBlock    A pointer to a working directory parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult     OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume reference number or a working directory reference number.Æ     ioWDDirID    LongInt    The directory ID.DESCRIPTIONPBHSetVol sets the default volume and directory to the volume and directory specified by the ioNamePtr, ioVRefNum, and ioWDDirID fields.PBHSetVol sets the default volume to the volume specified by the ioVRefNum field, which can contain either a volume reference number or a working directory reference number. If the ioNamePtr field specifies a full pathname, however, the default volume is set to the volume whose name is contained in that pathname. (A full pathname overrides the ioVRefNum field.)PBHSetVol also sets the default directory. If the ioVRefNum field contains a volume reference number, then the default directory is set to the directory on that volume having the partial pathname specified by ioNamePtr in the directory specified by ioWDDirID. If ioNamePtr is NIL, the default directory is simply the directory whose directory ID is contained in ioWDDirID.If the ioVRefNum field contains a working directory reference number, then ioWDDirID is ignored and the default directory is set to the directory on that volume having the partial pathname specified by ioNamePtr in the directory specified by the working directory reference number. If ioNamePtr is NIL, the default directory is simply the directory encoded in ioVRefNum.Use of the PBHSetVol function is discouraged if your application may execute in system software versions prior to version 7.0. Because the specified directory might not itself be a working directory, PBHSetVol records the default volume and directory separately, using the volume reference number of the volume and the actual directory ID of the specified directory. Subsequent calls to GetVol (or PBGetVol) return only the volume reference number, which will cause that volume’s root directory to be accessed (rather than the default directory, as expected).<36pt\>\x12 <8bat\>s Both the default volume and the default directory are used in calls made with no volume name and a volume reference number of zero.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errornsvErr    –35    No such volumebdNamErr    –37    Bad volume namefnfErr    –43    Directory not foundparamErr    –50    No default volumeFile System Specification RoutinesThe File Manager provides a set of file and directory manipulation routines that accept file system specification records as parameters. Depending on the requirements of your application and on the environment in which it is running, you may be able to accomplish all your file and directory operations by using these routines.Before calling any of these routines, however, you should ensure that they are available in the operating environment by calling the Gestalt function. If these routines are not available, you can call the corresponding HFS routines. See “High-Level HFS Routines” later in this chapter for details.Opening FilesThere are two FSSpec functions that allow you to open files, FSpOpenDF and FSpOpenRF. You can use them to open a file’s data fork and resource fork, respectively.2FSpOpenDFYou can use the FSpOpenDF function to open a file’s data fork.FUNCTION FSpOpenDF (spec: FSSpec; permission: SignedByte;                            VAR refNum: Integer): OSErr;spec    An FSSpec record specifying the file whose data fork is to be opened.permission    A constant indicating the desired file access permissions. See the list of constants in the description that follows.refNum    A reference number of an access path to the file’s data fork.DESCRIPTIONThe FSpOpenDF function opens the data fork of the file specified by the spec parameter and returns an access path reference number to that fork in the refNum parameter. You can pass that reference number as a parameter to any of the low- or high-level file access routines. Like the function HOpenDF (but unlike HOpen), FSpOpenDF allows you to open even a file whose name begins with a period (.).The permission parameter specifies the kind of access path permission you want. In most cases, you can simply set the permission parameter to fsCurPerm. Some applications request fsRdWrPerm, to ensure that they can both read from and write to a file. For more information about permissions, see “File Manipulation” earlier in this chapter. In shared environments, permission requests are translated into the “deny-mode” permissions defined by AppleShare.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenametmfoErr    –42    Too many files openfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr    –54    Attempt to open locked file for writingdirNFErr    –120    Directory not found or incomplete pathname2FSpOpenRFYou can use the FSpOpenRF function to open a file’s resource fork.FUNCTION FSpOpenRF (spec: FSSpec; permission: SignedByte;                            VAR refNum: Integer): OSErr;spec    An FSSpec record specifying the file whose resource fork is to be opened.permission    A constant indicating the desired file access permissions.refNum    A reference number of an access path to the file’s resource fork.DESCRIPTIONThe FSpOpenRF function creates an access path to the resource fork of a file and returns an access path reference number to that fork in the refNum parameter. You can pass that reference number as a parameter to any of the low- or high-level file access routines. The permission parameter should contain one of the constants listed in the description of FSpOpenDF in the previous section.SPECIAL CONSIDERATIONSNormally your application should access a file’s resource fork using Resource Manager routines rather than File Manager routines. The FSpOpenRF function does not read the resource map into memory and is generally useful only for applications that need block-level access to a resource fork (such as a utility that copies files).RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenametmfoErr    –42    Too many files openfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr    –54    Attempt to open locked file for writingdirNFErr    –120    Directory not found or incomplete pathnameCreating and Deleting Files and DirectoriesYou can create files and directories by calling FSpCreate and FSpDirCreate, respectively. You can delete files and directories by calling the FSpDelete function.2FSpCreateYou can use the FSpCreate function to create a new file.FUNCTION FSpCreate (spec: FSSpec; creator: OSType;                             fileType: OSType; scriptTag: ScriptCode):                             OSErr;spec    An FSSpec record specifying the file to be created.creator    The creator of the new file.fileType    The file type of the new file.scriptTag    The code of the script system in which the file’s name is to be displayed. If you have established the name and location of the new file using either the StandardPutFile or CustomPutFile procedure, specify the script code returned in the reply record. (See the Standard File Package chapter in this volume for a description of StandardPutFile and CustomPutFile.) Otherwise, specify the system script by setting the scriptTag parameter to the value smSystemScript.DESCRIPTIONThe FSpCreate function creates a new file (both forks) with the specified type, creator, and script code. The new file is unlocked and empty. The date and time of creation and last modification are set to the current date and time.See the Finder Interface chapter in the Toolbox volume for information on file types and creators.Files created using FSpCreate are not automatically opened. If you want to write data into the new file, you must first open the file using a file access routine (such as FSpOpenDF).RESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamewPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and version2FSpDirCreateYou can use the FSpDirCreate function to create a new directory.FUNCTION FSpDirCreate (spec: FSSpec; scriptTag: ScriptCode;                                 VAR createdDirID: LongInt): OSErr;spec    An FSSpec record specifying the directory to be created.scriptTag    The code of the script system in which the directory name is to be displayed. If you have established the name and location of the new directory using either the StandardPutFile or CustomPutFile procedure, specify the script code returned in the reply record. (See the Standard File Package chapter in this volume for a description of StandardPutFile and CustomPutFile.) Otherwise, specify the system script by setting the scriptTag parameter to the value smSystemScript.createdDirIDThe directory ID of the directory that was created.DESCRIPTIONThe FSpDirCreate function creates a new directory and returns the directory ID of the new directory in the createdDirID parameter. FSpDirCreate sets the date and time of creation and last modification to the current date and time.RESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamewPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versiondirNFErr    –120    Directory not found or incomplete pathname2FSpDeleteYou can use the FSpDelete function to delete files and directories.FUNCTION FSpDelete (spec: FSSpec): OSErr;spec    An FSSpec record specifying the file or directory to delete.DESCRIPTIONThe FSpDelete function removes a file or directory. If the specified target is a file, both forks of the file are deleted. In addition, if a file ID reference for the specified file exists, that file ID reference is removed.A file must be closed before you can delete it. Similarly, a directory must be empty before you can delete it. If you attempt to delete an open file or a nonempty directory, FSpDelete returns the result code fBsyErr.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockfBsyErr    –47    File busy, directory not empty, or working        directory control block opendirNFErr    –120    Directory not found or incomplete pathnameAccessing Information about Files and DirectoriesThe File Manager provides a number of FSSpec routines that allow you to obtain and set information about files and directories and to manipulate file locking. These routines don’t require the file to be open.2FSpGetFInfoYou can use the FSpGetFInfo function to obtain the Finder information about a file or directory.FUNCTION FSpGetFInfo (spec: FSSpec; VAR fndrInfo: FInfo): OSErr;spec    An FSSpec record specifying the file or directory whose Finder information is desiredfndrInfo    Information used by the Finder.DESCRIPTIONThe FSpGetFInfo function returns the Finder information from the volume catalog entry for the specified file or directory. FSpGetFInfo provides only the original Finder information—the FInfo and DInfo records, not FXInfo or DXInfo. (See the Finder Interface chapter in the Toolbox volume for a discussion of Finder information.)RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundparamErr    –50    No default volumedirNFErr    –120    Directory not found or incomplete pathname2FSpSetFInfoYou can use the FSpSetFInfo function to set the Finder information about a file or directory.FUNCTION FSpSetFInfo (spec: FSSpec; fndrInfo: FInfo): OSErr;spec    An FSSpec record specifying the file or directory whose Finder information will be set.fndrInfo    Information to be used by the Finder.DESCRIPTIONThe FSpSetFInfo function changes the Finder information in the volume catalog entry for the specified file or directory. FSpSetFInfo allows you to set only the original Finder information—the FInfo or DInfo records, not FXInfo or DXInfo. (See the Finder Interface chapter in the Toolbox volume for a discussion of Finder information.)RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockdirNFErr    –120    Directory not found or incomplete pathname2FSpSetFLockYou can use the FSpSetFLock function to lock a file.FUNCTION FSpSetFLock (spec: FSSpec): OSErr; spec    An FSSpec record specifying the file to lock.DESCRIPTIONThe FSpSetFLock function locks a file. After you lock a file, all new access paths to that file are read-only. Any access paths to that file that are currently in use are not affected by FSpSetFLock.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorfnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdirNFErr    –120    Directory not found or incomplete pathname2FSpRstFLockYou can use the FSpRstFLock function to unlock a file.FUNCTION FSpRstFLock (spec: FSSpec): OSErr;spec    An FSSpec record specifying the file to unlock.DESCRIPTIONThe FSpRstFLock function unlocks a file. Any access paths to that file that are currently in use are not affected by FSpRstFLock.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorfnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdirNFErr    –120    Directory not found or incomplete pathname2FSpRenameYou can use the FSpRename function to rename a file or directory.FUNCTION FSpRename (spec: FSSpec; newName: Str255): OSErr;spec    An FSSpec record specifying the file or directory to rename.newName    The new name of the file or directory.DESCRIPTIONThe FSpRename function changes the name of a file or directory. If a file ID reference for the specified file exists, it remains with the renamed file.SPECIAL CONSIDERATIONSIf you want to change the name of a new copy of an existing file, you should use the FSpExchangeFiles function instead. RESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr     –45    File lockedvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versionparamErr    –50    No default volumefsRnErr     –59    Problem during renamedirNFErr    –120    Directory not found or incomplete pathnameMoving Files or DirectoriesThe FSpCatMove function allows you to move files and directories within a volume. If the FSSpec routines are not available, you can call the high-level HFS routine CatMove or the low-level HFS routine PBCatMove.2FSpCatMoveYou can use the FSpCatMove function to move a file or directory from one location to another on the same volume.FUNCTION FSpCatMove (source: FSSpec; dest: FSSpec): OSErr;source    An FSSpec record specifying the name and location of the file or directory before the move.dest    An FSSpec record specifying the name and location of the file or directory after the move.DESCRIPTIONThe FSpCatMove function moves the file or directory specified by the source parameter to the destination specified by the dest parameter. FSpCatMove is strictly a file catalog operation; it does not actually change the location of the file or directory on the disk.FSpCatMove cannot move a file or directory to another volume (that is, the vRefNum field in both FSSpec parameters must be the same). It also cannot be used to rename files or directories; to rename a file or directory, use FSpRename.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filename or attempt to move into a filefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versionparamErr    –50    No default volumebadMovErr    –122    Attempt to move into offspringExchanging the Data in Two FilesThe FSpExchangeFiles function allows you to exchange the data in two files.2FSpExchangeFilesYou can use the FSpExchangeFiles function to exchange the data stored in two files on the same volume.FUNCTION FSpExchangeFiles (source: FSSpec; dest: FSSpec): OSErr;source    The file whose contents and file information are placed into the file specified by the dest parameter.dest    The file whose contents and file information are placed into the file specified by the source parameter.DESCRIPTIONFSpExchangeFiles swaps the data in two files by changing the information in the volume’s catalog and, if the files are open, in the file control blocks. You should use FSpExchangeFiles when updating an existing file, so that if the file is being tracked through its file ID, the ID remains valid. FSpExchangeFiles changes the fields in the catalog entries that record the location of the data and the modification dates. It swaps both the data forks and the resource forks.FSpExchangeFiles works on either open or closed files. If either file is open, FSpExchangeFiles updates any file control blocks associated with the file. Exchanging the contents of two files requires essentially the same access permissions as opening both files for writing.The files whose data is to be exchanged must both reside on the same volume. If they do not, FSpExchangeFiles returns the result code diffVolErr.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundioErr    –36    I/O errorfnfErr    –43    File not foundfLckdErr    –45    File lockedvolOfflinErr    –53    Volume is off linewrgVolTypeErr    –123    Not an HFS volumenotAFileErr    –1302    Specified file is a directorydiffVolErr    –1303    Files are on different volumessameFileErr    –1306    Source and destination are the sameCreating File System SpecificationsYou can use either the FSMakeFSSpec function or the PBMakeFSSpec function to create FSSpec records. You should always use FSMakeFSSpec or PBMakeFSSpec to create an FSSpec record rather than allocating space and filling out the fields of the record yourself.2FSMakeFSSpecYou can use the FSMakeFSSpec function to create an FSSpec record for a file or directory.FUNCTION FSMakeFSSpec (vRefNum: Integer; dirID: LongInt;                                 fileName: Str255; VAR spec: FSSpec):                                 OSErr;vRefNum    A volume specification. This parameter can contain a volume reference number, a working directory reference number, a drive number, or 0 (to specify the default volume).dirID    A directory specification. This parameter is usually the parent directory ID of the target object. If the directory is sufficiently specified by either the vRefNum or fileName parameter, dirID can be 0. If you explicitly specify dirID (that is, if it is any value other than 0), and if vRefNum is a working directory reference number, dirID overrides the directory ID included in vRefNum. If the fileName parameter is an empty string, FSMakeFSSpec creates an FSSpec record for a directory specified by either the dirID or vRefNum parameter.fileName    A full or partial pathname. If it is a full pathname, FSMakeFSSpec ignores both the vRefNum and dirID parameters. A partial pathname might identify only the final target, or it might include one or more parent directory names. If fileName is a partial pathname, then vRefNum, dirID, or both must be valid.spec    A file system specification to be filled in by FSMakeFSSpec.DESCRIPTIONFSMakeFSSpec fills in the fields of the spec parameter using the information contained in the other three parameters. Call FSMakeFSSpec whenever you want to create an FSSpec record.You can pass the input to FSMakeFSSpec in any of the four ways described in “HFS Specifications” earlier in this chapter. See Table 2-8 in “Creating File System Specification Records” earlier in this chapter for information about the way FSMakeFSSpec interprets its input.If the specified volume is mounted and the specified parent directory exists, but the target file or directory doesn’t exist in that location, FSMakeFSSpec fills in the record and then returns fnfErr instead of noErr. The record is valid, but it describes a target that doesn’t exist. You can use the record for other operations, such as creating a file with the FSpCreate function.In addition to the result codes that follow, FSMakeFSSpec can return a number of different File Manager error codes. If your application receives any result code other than noErr or fnfErr, all fields of the resulting FSSpec record are set to 0.RESULT CODESnoErr    0    No errornsvErr    –35    Volume doesn’t existfnfErr    –43    File or directory does not exist        (FSSpec is still valid)2PBMakeFSSpecYou can use the low-level PBMakeFSSpec function to create an FSSpec record for a file or directory.FUNCTION PBMakeFSSpec (paramBlock: HParmBlkPtr; async: Boolean)                             : OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a file or directory name.Æ     ioVRefNum    Integer    A volume specification.Æ     ioMisc    LongInt    A pointer to an FSSpec record.Æ     ioDirID    LongInt    A parent directory ID.DESCRIPTIONGiven a complete specification for a file or directory, PBMakeFSSpec fills in an FSSpec record that identifies the file or directory. (See Table 2-8 in “Creating File System Specification Records” for a detailed description of valid file specifications.)If the specified volume is mounted and the specified parent directory exists, but the target file or directory doesn’t exist in that location, PBMakeFSSpec fills in the record and returns fnfErr instead of noErr. The record is valid, but it describes a target that doesn’t exist. You can use the record for another operation, such as creating a file.In addition to the result codes that follow, PBMakeFSSpec can return a number of different File Manager error codes. When PBMakeFSSpec returns any result other than noErr or fnfErr, all fields of the resulting FSSpec record are set to 0.RESULT CODESnoErr    0    No errornsvErr    –35    Volume doesn’t existfnfErr    –43    File or directory does not exist        (FSSpec is still valid)High-Level HFS RoutinesThe File Manager provides a set of high-level file and directory manipulation routines that are available in all operating environments. You may need to use these routines if the FSSpec routines are not available. You do not need to call the Gestalt function to determine if these routines are available.Each of the high-level HFS routines allows you to specify a file or directory by providing three parameters: a volume specification, a directory specification, and a filename. See “HFS Specifications” earlier in this chapter for a complete description of the many ways in which you can set these parameters to pick out a file or directory.Opening FilesYou can use the functions HOpenDF, HOpenRF, and HOpen to open files.2HOpenDFYou can use the HOpenDF function to open the data fork of a file.FUNCTION HOpenDF (vRefNum: Integer; dirID: LongInt;                         fileName: Str255; permission: SignedByte;                         VAR refNum: Integer): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.fileName    The name of the file.permission    The access mode under which to open the file.refNum    The file reference number of the opened file.DESCRIPTIONThe HOpenDF function creates an access path to the data fork of a file and returns an access path reference number to that fork in the refNum parameter. You can pass that reference number as a parameter to any of the high-level file access routines.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenametmfoErr    –42    Too many files openfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr    –54    Attempt to open locked file for writingdirNFErr    –120    Directory not found or incomplete pathname2HOpenRFYou can use the HOpenRF function to open the resource fork of file.FUNCTION HOpenRF (vRefNum: Integer; dirID: LongInt;                         fileName: Str255; permission: SignedByte;                         VAR refNum: Integer): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.fileName    The name of the file.permission    The access mode under which to open the file.refNum    The file reference number of the opened file.DESCRIPTIONThe HOpenRF function creates an access path to the resource fork of a file. A file reference number for that file is returned in the refNum parameter.SPECIAL CONSIDERATIONSNormally your application should access a file’s resource fork using Resource Manager routines rather than File Manager routines. The HOpenRF function does not read the resource map into memory and is generally useful only for applications that need block-level access to a resource fork (such as a utility that copies files).RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenametmfoErr    –42    Too many files openfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr    –54    Attempt to open locked file for writingdirNFErr    –120    Directory not found or incomplete pathname2HOpenYou can use the HOpen function to open the data fork of a file. Because HOpen will also open devices, it’s safer to use the HOpenDF function instead.FUNCTION HOpen (vRefNum: Integer; dirID: LongInt;                         fileName: Str255; permission: SignedByte;                         VAR refNum: Integer): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.fileName    The name of the file.permission    The access mode under which to open the file.refNum    The file reference number of the opened file.DESCRIPTIONHOpen creates an access path to the data fork of the specified file. A path reference number for that file is returned in the refNum parameter.If you use HOpen to try to open a file whose name begins with a period (.), you might mistakenly open a driver instead; subsequent attempts to write data might corrupt data on the target device. To avoid these problems, you should always use HOpenDF instead of HOpen.<36pt\>\x12 <8bat\>sRESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenametmfoErr    –42    Too many files openfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr    –54    Attempt to open locked file for writingdirNFErr    –120    Directory not found or incomplete pathnameCreating and Deleting Files and DirectoriesYou can create a file by calling the HCreate function and a directory by calling the DirCreate function. To delete either a file or a directory, call HDelete.2HCreateYou can use the HCreate function to create a new file.FUNCTION HCreate (vRefNum: Integer; dirID: LongInt;                         fileName: Str255; creator: OSType;                         fileType: OSType): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.fileName    The name of the new file.creator    The creator of the new file.fileType    The file type of the new file.DESCRIPTIONHCreate creates a new file (both forks) with the specified name, creator, and file type. For information on a file’s creator and type, see the Finder Interface chapter in the Toolbox volume.The new file is unlocked and empty. The date and time of its creation and last modification are set to the current date and time.Files created using HCreate are not automatically opened. If you want to write data into the new file, you must first open the file using a file access routine.You should not allow users to create files having names beginning with a period (.). This ensures that those files can successfully be opened by applications calling HOpen instead of HOpenDF.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamewPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versiondirNFErr    –120    Directory not found or incomplete pathname2DirCreateYou can use the DirCreate function to create a new directory.FUNCTION DirCreate (vRefNum: Integer; parentDirID: LongInt;                             dirName: Str255;                             VAR createdDirID: LongInt): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.parentDirIDThe directory ID of the parent directory; if it’s 0, the new directory is placed in the root directory of the specified volume.dirName    The name of the new directory.createdDirIDThe directory ID of the created directory.DESCRIPTIONDirCreate creates a new directory and returns the directory ID of the new directory in the createdDirID parameter. The date and time of its creation and last modification are set to the current date and time.A directory ID, unlike a volume reference number or a working directory reference number, is a LongInt.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamewPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versiondirNFErr    –120    Directory not found or incomplete pathname2HDeleteYou can use the HDelete function to delete a file or directory.FUNCTION HDelete (vRefNum: Integer; dirID: LongInt;                         fileName: Str255): OSErr;vRefNum    A volume specification (a volume reference number, a working directory reference number, or 0 for the default volume).dirID    The directory ID of the parent of the file or directory to delete.fileName    The name of the file or directory to delete.DESCRIPTIONThe HDelete function removes a file or directory. If the specified target is a file, both forks of the file are deleted. In addition, if a file ID reference for the specified file exists, that reference is removed.A file must be closed before you can delete it. Similarly, a directory must be empty before you can delete it. If you attempt to delete an open file or a nonempty directory, HDelete returns the result code fBsyErr.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockfBsyErr    –47    File busy, directory not empty, or working        directory control block opendirNFErr    –120    Directory not found or incomplete pathnameAccessing Information about Files and DirectoriesThe File Manager provides a number of high-level HFS routines that allow you to obtain and set information about files and directories and to manipulate file locking. All of the routines described in this section operate on both forks of a file, and don’t require the file to be open.2HGetFInfoYou can use the HGetFInfo function to obtain the Finder information for a file.FUNCTION HGetFInfo (vRefNum: Integer; dirID: LongInt;                             fileName: Str255; VAR fndrInfo: FInfo):                             OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.fileName    The name of the file.fndrInfo    Information used by the Finder.DESCRIPTIONThe HGetFInfo function returns the Finder information stored in the volume’s catalog for a file. See the Finder Interface chapter in the Toolbox volume for details about Finder information.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundparamErr    –50    No default volumedirNFErr    –120    Directory not found or incomplete pathname2HSetFInfoYou can use the HSetFInfo function to set the Finder information for a file.FUNCTION HSetFInfo (vRefNum: Integer; dirID: LongInt;                             fileName: Str255; fndrInfo: FInfo): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.fileName    The name of the file.fndrInfo    Information used by the Finder.DESCRIPTIONThe HSetFInfo function changes the Finder information stored in the volume’s catalog for a file. See the “Finder Interface” chapter in the Toolbox volume for details about Finder information.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockdirNFErr    –120    Directory not found or incomplete pathname2HSetFLockYou can use the HSetFLock function to lock a file.FUNCTION HSetFLock (vRefNum: Integer; dirID: LongInt;                             fileName: Str255): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.fileName    The name of the file.DESCRIPTIONThe HSetFLock function locks a file.  After you lock a file, all new access paths to that file are read-only. Any access paths to that file that are currently in use are not affected by HSetFLock.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorfnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdirNFErr    –120    Directory not found or incomplete pathname2HRstFLockYou can use the HRstFLock function to unlock a file.FUNCTION HRstFLock (vRefNum: Integer; dirID: LongInt;                             fileName: Str255): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.fileName    The name of the file.DESCRIPTIONThe HRstFLock function unlocks a file. Any access paths to that file that are currently in use are not affected by HRstFLock.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorfnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdirNFErr    –120    Directory not found or incomplete pathname2HRenameYou can use the HRename function to rename a file, directory, or volume.FUNCTION HRename (vRefNum: Integer; dirID: LongInt;                         oldName: Str255; newName: Str255): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.oldName    An existing filename, directory name, or volume name.newName    The new filename, directory name, or volume name.DESCRIPTIONThe HRename function changes the name of a file, directory, or volume. Given the name of a file or directory in oldName, HRename changes it to the name in newName. Given a volume name or a volume reference number, it changes the name of the volume to the name in newName. Access paths currently in use aren’t affected. SPECIAL CONSIDERATIONSHRename cannot be used to change which directory a file is in. If you’re renaming a volume, make sure that both names end with a colon.If a file ID reference exists for a file you are renaming, the file ID remains with the renamed file.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr     –45    File lockedvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filenameparamErr    –50    No default volumefsRnErr     –59    Problem during renamedirNFErr    –120    Directory not found or incomplete pathnameMoving Files or DirectoriesThe  high-level HFS function CatMove allows you to move files and directories within a volume.2CatMoveYou can use the CatMove function to move files or directories from one directory to another on the same volume.FUNCTION CatMove (vRefNum: Integer; dirID: LongInt;                         oldName: Str255; newDirID: LongInt;                         newName: Str255): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.oldName    An existing filename or directory name.newDirID    If NewName is empty, the directory ID of the target directory; otherwise, the parent directory ID of the target directory.newName    The name of the directory to which the file or directory is to be moved.DESCRIPTIONCatMove moves a file or directory from one directory to another within a volume. CatMove is strictly a file catalog operation; it does not actually change the location of the file or directory on the disk.CatMove cannot move a file or directory to another volume (that is, the vRefNum parameter is used in specifying both the source and the destination). It also cannot be used to rename files or directories; to rename a file or directory, use HRename.The name of the directory to which the file or directory is to be moved is specified by the NewName parameter. If a valid directory name is provided for NewName, the destination directory’s parent directory is specified in NewDirID. However, you can specify an empty name for NewName, in which case NewDirID should be set to the directory ID of the destination directory.It is usually simplest to specify the destination directory by passing its directory ID in the NewDirID parameter and by setting NewName to an empty name. To specify an empty name, set NewName to ':'.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filename or attempt to move into a filefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versionparamErr    –50    No default volumebadMovErr    –122    Attempt to move into offspringMaintaining Working DirectoriesThe File Manager provides several functions that allow you to manipulate working directories. Working directories are used internally by the File Manager; in general, your application should not create or directly access working directories.2OpenWDYou can use the OpenWD function to create a working directory.FUNCTION OpenWD (vRefNum: Integer; dirID: LongInt;                         procID: LongInt; VAR wdRefNum: Integer): OSErr;vRefNum    A volume reference number, a working directory reference number, or 0 for the default volume.dirID    A directory ID.procID    A working directory user identifier. You should use your application’s signature as the user identifier.wdRefNum    The working directory reference number.DESCRIPTIONOpenWD takes the specified directory and makes it a working directory. It returns a working directory reference number in wdRefNum that can be used in subsequent calls.If a given directory has already been made a working directory using the same user identifier, no new working directory will be opened; instead, the existing working directory reference number will be returned. If a given directory was already made a working directory using a different user identifier, a new working directory reference number is returned.RESULT CODESnoErr    0    No errortmwdoErr    –121    Too many working directories open2CloseWDYou can use the CloseWD function to close a working directory.FUNCTION CloseWD (wdRefNum: Integer): OSErr;wdRefNum    A working directory reference number.DESCRIPTIONCloseWD releases the specified working directory. If you specify a volume reference number in the wdRefNum parameter, CloseWD does nothing.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errornsvErr    –35    No such volume2GetWDInfoYou can use the GetWDInfo function to get information about a working directory.FUNCTION GetWDInfo (wdRefNum: Integer; VAR vRefNum: Integer;                             VAR dirID: LongInt; VAR procID: LongInt):                             OSErr;wdRefNum    A working directory reference numbervRefNum    If nonzero on input, a volume reference number or drive number. On output, the volume reference number of the working directory.dirID    On output, the directory ID of the specified working directory.procID    The working directory user identifier.DESCRIPTIONGetWDInfo returns information about the specified working directory. You can use GetWDInfo to convert a working directory reference number into its corresponding volume reference number and directory ID.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeLow-Level HFS RoutinesThe File Manager provides a set of low-level file and directory manipulation routines that are available in all operating environments. You do not need to call the Gestalt function to determine if these routines are available.These routines exchange parameters with your application through a parameter block. When you call a low-level routine, you pass the address of the appropriate parameter block to the routine.Some low-level HFS routines can run either asynchronously or synchronously. Each of these routines comes in three versions: one version requires the async parameter, and two have the suffix “Async” or “Sync” added to their names. For more information about the differences between the three versions, see “Low-Level File Access Routines” earlier in this chapter. Only the first version of these routines is documented in this section. See the Summary at the end of this chapter for a listing that includes all three versions.Opening FilesYou can use the functions PBHOpenDF, PBHOpenRF, and PBHOpen to open files.2PBHOpenDFYou can use the PBHOpenDF function to open the data fork of a file.FUNCTION PBHOpenDF (paramBlock: HParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.¨     ioRefNum    Integer    A file reference number.Æ     ioPermssn    SignedByte    The read/write permission.Æ     ioDirID    LongInt    A parent directory ID.DESCRIPTIONThe PBHOpenDF function creates an access path to the data fork of a file and returns a file reference number in the ioRefNum field. PBHOpenDF is exactly like the PBHOpen function except that PBHOpenDF allows you to open a file whose name begins with a period (.).A path can be opened for writing even if it accesses a file on a locked volume, and an error won’t be returned until a PBWrite, PBSetEOF, or PBAllocate call is made.If you attempt to open a locked file for writing, PBHOpenDF returns the result code permErr. If you request exclusive read/write permission but another access path is already open, PBHOpenDF returns the reference number of the existing access path in ioRefNum and opWrErr as its function result.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenametmfoErr    –42    Too many files openfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr    –54    Attempt to open locked file for writingdirNFErr    –120    Directory not found or incomplete pathname2PBHOpenRFYou can use the PBHOpenRF function to open the resource fork of file.FUNCTION PBHOpenRF (paramBlock: HParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.¨     ioRefNum    Integer    A file reference number.Æ     ioPermssn    SignedByte    The read/write permission.Æ     ioDirID    LongInt    A directory ID.DESCRIPTIONThe PBHOpenRF function creates an access path to the resource fork of a file and returns a file reference number in the ioRefNum field.SPECIAL CONSIDERATIONSNormally your application should access a file’s resource fork using Resource Manager routines rather than File Manager routines. The PBHOpenRF function does not read the resource map into memory and is generally useful only for applications that need block-level access to a resource fork (such as a utility that copies files).RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenametmfoErr    –42    Too many files openfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr    –54    Attempt to open locked file for writingdirNFErr    –120    Directory not found or incomplete pathname2PBHOpenYou can use the PBHOpen function to open the data fork of a file. Because PBHOpen will also open devices, it’s safer to use the PBHOpenDF function instead.FUNCTION PBHOpen (paramBlock: HParmBlkPtr; async: Boolean): OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.¨     ioRefNum    Integer    A file reference number.Æ     ioPermssn    SignedByte    The read/write permission.Æ     ioDirID    LongInt    A directory ID.DESCRIPTIONThe PBHOpen function creates an access path to the data fork of the specified file and returns a file reference number in the ioRefNum field.A path can be opened for writing even if it accesses a file on a locked volume, and an error won’t be returned until a PBWrite, PBSetEOF, or PBAllocate call is made.If you attempt to open a locked file for writing, PBHOpen returns the result code permErr. If you request exclusive read/write permission but another access path is already open, PBHOpen returns the reference number of the existing access path in ioRefNum and opWrErr as its function result.If you use PBHOpen to try to open a file whose name begins with a period, you might mistakenly open a driver instead; subsequent attempts to write data might corrupt data on the target device. To avoid these problems, you should always use PBHOpenDF instead of PBHOpen.<36pt\>\x12 <8bat\>sRESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenametmfoErr    –42    Too many files openfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr    –54    Attempt to open locked file for writingdirNFErr    –120    Directory not found or incomplete pathnameCreating and Deleting Files and DirectoriesYou can create a file by calling the PBHCreate function and a directory by calling the PBDirCreate function. To delete either a file or a directory, use PBHDelete.2PBHCreateYou can use the PBHCreate function to create a new file.FUNCTION PBHCreate (paramBlock: HParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioDirID    LongInt    A directory ID.DESCRIPTIONPBHCreate creates a new file (both forks); the new file is unlocked and empty. The date and time of its creation and last modification are set to the current date and time. If the file created isn’t temporary (that is, if it will exist after the user quits the application), the application should call PBHSetFInfo (after PBHCreate) to fill in the information needed by the Finder.Files created using PBHCreate are not automatically opened. If you want to write data into the new file, you must first open the file using a file access routine (such as PBHOpenDF).RESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamewPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versiondirNFErr    –120    Directory not found or incomplete pathname2PBDirCreateYou can use the PBDirCreate function to create a new directory.FUNCTION PBDirCreate (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.´     ioNamePtr     StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.´     ioDirID    LongInt    A directory ID.DESCRIPTIONPBDirCreate is identical to PBHCreate except that it creates a new directory instead of a file. You can specify the parent of the directory to be created in ioDirID; if it’s 0, the new directory is placed in the root directory of the specified volume. The directory ID of the new directory is returned in ioDirID. The date and time of its creation and last modification are set to the current date and time.A directory ID, unlike a volume reference number or a working directory reference number, is a LongInt.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamewPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versiondirNFErr    –120    Directory not found or incomplete pathname2PBHDeleteYou can use the PBHDelete function to delete a file or directory.FUNCTION PBHDelete (paramBlock: HParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioDirID    LongInt    A directory ID.DESCRIPTIONThe PBHDelete function removes a file or directory. If the specified target is a file, both forks of the file are deleted. In addition, if a file ID reference for the specified file exists, that file ID reference is also removed.A file must be closed before you can delete it. Similarly, a directory must be empty before you can delete it. If you attempt to delete an open file or a nonempty directory, PBHDelete returns the result code fBsyErr.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockfBsyErr    –47    File busy, directory not empty, or working        directory control block opendirNFErr    –120    Directory not found or incomplete pathnameAccessing Information about Files and DirectoriesThe File Manager provides a number of low-level HFS routines that allow you to obtain and set information about files and directories and to manipulate file locking. All of the routines described in this section operate on both forks of a file, and don’t require the file to be open.2PBGetCatInfoYou can use the PBGetCatInfo function to get information about the files and directories in a file catalog.FUNCTION PBGetCatInfo (paramBlock: CInfoPBPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a catalog information parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Parameter block for filesÆ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.´     ioNamePtr     StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.¨     ioFRefNum    Integer    A file reference number.Æ     ioFDirIndex    Integer    An index.¨     ioFlAttrib    SignedByte    The file attributes.¨     ioFlFndrInfo    FInfo    Information used by the Finder.´     ioDirID    LongInt    On input, a directory ID. On output, a file ID.¨     ioFlStBlk     Integer    The first allocation block of the data fork.¨     ioFlLgLen    LongInt    The logical end-of-file of the data fork.¨     ioFlPyLen    LongInt    The physical end-of-file of the data fork.¨     ioFlRStBlk    Integer    The first allocation block of the resource fork.¨     ioFlRLgLen    LongInt    The logical end-of-file of the resource fork.¨     ioFlRPyLen    LongInt    The physical end-of-file of the resource fork.¨     ioFlCrDat    LongInt    The date and time of creation.¨     ioFlMdDat    LongInt    The date and time of the last modification.¨     ioFlBkDat    LongInt    The date and time of the last backup.¨     ioFlXFndrInfo    FXInfo    Additional information used by the Finder.¨     ioFlParID    LongInt    The directory ID of the parent directory.¨     ioFlClpSiz    LongInt    The file’s clump size.Parameter block for directoriesÆ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.´     ioNamePtr     StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioFDirIndex    Integer    An index.¨     ioFlAttrib    SignedByte    The directory attributes.¨     ioACUser    SignedByte    The directory access rights.¨     ioDrUsrWds    DInfo    Information used by the Finder.´     ioDrDirID    LongInt    The directory ID.¨     ioDrNmFls    Integer    The number of files in the directory.¨     ioDrCrDat    LongInt    The date and time of creation.¨     ioDrMdDat    LongInt    The date and time of the last modification.¨     ioDrBkDat    LongInt    The date and time of the last backup.¨     ioDrFndrInfo    DXInfo    Additional information used by the Finder.¨     ioDrParID    LongInt    The directory ID of the parent directory.DESCRIPTIONPBGetCatInfo returns information about a file or directory, depending on the values you specify in the ioFDirIndex, ioNamePtr, ioVRefNum, and ioDirID or ioDrDirID fields. If you need to determine whether the information returned is for a file or a directory, you can test bit 4 of the ioFlAttrib field; if that bit is set, the information returned describes a directory.PBGetCatInfo selects a file or directory according to these rules:n    If ioFDirIndex is positive, PBGetCatInfo returns information about the file or directory whose directory index is ioFDirIndex in the directory specified by ioVRefNum (this will be the root directory if a volume reference number is provided).n    If ioFDirIndex is 0, PBGetCatInfo returns information about the file or directory specified by ioNamePtr in the directory specified by ioVRefNum (again, this will be the root directory if a volume reference number is provided).n    If ioFDirIndex is negative, PBGetCatInfo ignores ioNamePtr and returns information about the directory specified by ioDrDirID.With files, PBGetCatInfo is similar to PBHGetFInfo but returns some additional information. If the file is open, the reference number of the first access path found is returned in ioFRefNum, and the name of the file is returned in ioNamePtr (unless ioNamePtr is NIL). The file’s attributes are returned in the ioFlAttrib field. See the description of the fields of the CInfoPBRec data type for the meaning of the bits in this field.With directories, PBGetCatInfo returns information such as the directory attributes and, for server volumes, the directory access privileges of the user. The directory attributes are encoded by bits in the ioFlAttrib field and have these meanings:Bit    Meaning0    Set if the directory is locked.1    Reserved.2    Set if the directory is within a shared area of the directory hierarchy.3    Set if the directory is a share point that is mounted by some user.4    Set if the item is a directory.5    Set if the directory is a share point.6–7    Reserved.These bits in the ioFlAttrib field for directories are read-only. You cannot alter directory attributes by setting these bits using PBSetCatInfo. Instead, you can call PBHSetFLock and PBHRstFLock to lock and unlock a directory, and PBShare and PBUnshare to enable or disable file sharing on local directories.<36pt\>\x12 <8bat\>uPBGetCatInfo returns the directory access rights in the ioACUser field only for shared volumes. As a result, you should set this field to 0 before calling PBGetCatInfo.You can also use PBGetCatInfo to determine whether a file has a file ID reference. The value of the file ID is returned in the ioDirID field. Because that parameter could also represent a directory ID, call PBResolveFileID to see if the value is a real file ID. If you want to determine whether a file ID reference exists for a file and create one if it doesn’t, use PBCreateFileID, which will either create a file ID or return fidExists.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundparamErr    –50    No default volumedirNFErr    –120    Directory not found or incomplete pathname2PBSetCatInfoYou can use the PBSetCatInfo function to modify information about files and directories.FUNCTION PBSetCatInfo (paramBlock: CInfoPBPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a catalog information parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Parameter block for filesÆ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.´     ioNamePtr     StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioFlAttrib    SignedByte    The file attributes.Æ     ioFlFndrInfo    FInfo    Information used by the Finder.Æ     ioDirID    LongInt    The directory ID.Æ     ioFlCrDat    LongInt    The date and time of creation.Æ     ioFlMdDat    LongInt    The date and time of the last modification.Æ     ioFlBkDat    LongInt    The date and time of the last backup.Æ     ioFlXFndrInfo    FXInfo    Additional information used by the Finder.Parameter block for directoriesÆ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.´     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioFlAttrib    SignedByte    The directory attributes.Æ     ioDrUsrWds    DInfo    Information used by the Finder.Æ     ioDrDirID    LongInt    The directory ID.Æ     ioDrCrDat    LongInt    The date and time of creation.Æ     ioDrMdDat    LongInt    The date and time of the last modification.Æ     ioDrBkDat    LongInt    The date and time of the last backup.Æ     ioDrFndrInfo    DXInfo    Additional information used by the Finder.DESCRIPTIONPBSetCatInfo sets information about a file or directory. With files, it’s similar to PBHSetFInfo but lets you set some additional information.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundparamErr    –50    No default volumedirNFErr    –120    Directory not found or incomplete pathname2PBHGetFInfoYou can use the PBHGetFInfo function to obtain information about a file.FUNCTION PBHGetFInfo (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.´     ioNamePtr     StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.¨     ioFRefNum    Integer    A file reference number.Æ     ioFDirIndex    Integer    An index.¨     ioFlAttrib    SignedByte    The file attributes.¨     ioFlFndrInfo    FInfo    Information used by the Finder.´     ioDirID    LongInt    On input, a directory ID; on output, a file ID.¨     ioFlStBlk     Integer    The first allocation block of the data fork.¨     ioFlLgLen    LongInt    The logical end-of-file of the data fork.¨     ioFlPyLen    LongInt    The physical end-of-file of the data fork.¨     ioFlRStBlk    Integer    The first allocation block of the resource fork.¨     ioFlRLgLen    LongInt    The logical end-of-file of the resource fork.¨     ioFlRPyLen    LongInt    The physical end-of-file of the resource fork.¨     ioFlCrDat    LongInt    The date and time of creation.¨     ioFlMdDat    LongInt    The date and time of last modification.DESCRIPTIONIf ioFDirIndex is positive, PBHGetFInfo returns information about the file whose directory index is ioFDirIndex on the volume specified by ioVRefNum.If a working directory reference number is specified in ioVRefNum, the File Manager returns information about the file whose directory index is ioFDirIndex in the specified directory.<36pt\>\x12 <8bat\>uIf ioFDirIndex is negative or 0, PBHGetFInfo returns information about the file having the name pointed to by ioNamePtr on the volume specified by ioVRefNum. If the file is open, the reference number of the first access path found is returned in ioFRefNum, and the name of the file is returned in ioNamePtr (unless ioNamePtr is NIL).RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundparamErr    –50    No default volumedirNFErr    –120    Directory not found or incomplete pathname2PBHSetFInfoYou can use the PBHSetFInfo function to set information for a file.FUNCTION PBHSetFInfo (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioFlFndrInfo    FInfo    Information used by the Finder.Æ     ioDirID    LongInt    A directory ID.Æ     ioFlCrDat     LongInt    The date and time of creation.Æ     ioFlMdDat    LongInt    The date and time of last modification.DESCRIPTIONPBHSetFInfo sets information (including the date and time of creation and modification, and information needed by the Finder) about the file having the name pointed to by ioNamePtr on the volume specified by ioVRefNum. You should call PBHGetFInfo just before PBHSetFInfo, so the current information is present in the parameter block.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockdirNFErr    –120    Directory not found or incomplete pathname2PBHSetFLockYou can use the PBHSetFLock function to lock a file.FUNCTION PBHSetFLock (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioDirID    LongInt    A directory ID.DESCRIPTIONPBHSetFLock locks the file with the name pointed to by ioNamePtr on the volume specified by ioVRefNum. After you lock a file, all new access paths to that file are read-only. Access paths currently in use aren’t affected.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorfnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdirNFErr    –120    Directory not found or incomplete pathname2PBHRstFLockYou can use the PBHRstFLock function to unlock a file.FUNCTION PBHRstFLock (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioDirID    LongInt    A directory ID.DESCRIPTIONPBHRstFLock unlocks the file with the name pointed to by ioNamePtr on the volume specified by ioVRefNum. Access paths currently in use aren’t affected.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorfnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdirNFErr    –120    Directory not found or incomplete pathname2PBHRenameYou can use the PBHRename function to rename a file, directory, or volume.FUNCTION PBHRename (paramBlock: HParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioMisc    Ptr    A pointer to the new name for the file.Æ     ioDirID    LongInt    A directory ID.DESCRIPTIONGiven a pointer to the name of a file or directory in ioNamePtr, PBHRename changes it to the name pointed to by ioMisc. Given a pointer to a volume name in ioNamePtr or a volume reference number in ioVRefNum, it changes the name of the volume to the name pointed to by ioMisc. If a file ID reference exists for the file being renamed, the file ID remains with the file.<36pt\>\x12 <8bat\>uYou cannot use PBHRename to change the directory in which a file is located.<36pt\>\x12 <8bat\>s RESULT CODESnoErr    0    No errordirFulErr    –33    File directory fullnsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filenamefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr     –45    File lockedvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versionparamErr    –50    No default volumefsRnErr     –59    Problem during renamedirNFErr    –120    Directory not found or incomplete pathnameMoving Files or DirectoriesThe low-level HFS function PBCatMove allows you to move files and directories within a volume.2PBCatMoveYou can use the PBCatMove function to move files or directories from one directory to another on the same volume.FUNCTION PBCatMove (paramBlock: CMovePBPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a catalog move parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to the name of the file or directory to be moved.Æ     ioVRefNum    Integer    A volume specification.Æ     ioNewName    StringPtr    A pointer to the name of the directory to which the file or directory is to be moved.Æ     ioNewDirID    LongInt    The directory ID of the directory to which the file or directory is to be moved, if ioNewName is NIL. If ioNewName is not NIL, this is the parent directory ID of the directory to which the file or directory is to be movedÆ     ioDirID    LongInt    The directory ID of the file or directory to be moved.DESCRIPTIONPBCatMove moves a file or directory from one directory to another within a volume. PBCatMove is strictly a file catalog operation; it does not actually change the location of the file or directory on the disk.PBCatMove cannot move a file or directory to another volume (that is, ioVRefNum is used in specifying both the source and the destination). It also cannot be used to rename files or directories; to rename a file or directory, use PBHRename.The source file or directory should be specified by its parent directory ID and partial pathname. Pass the parent directory ID in the ioDirID field and a pointer to the partial pathname in the ioNamePtr field.The name of the directory to which the file or directory is to be moved is specified by the ioNewName field. If a valid directory name is provided for ioNewName, the destination directory’s parent directory is specified in ioNewDirID. However, you can specify NIL for ioNewName, in which case ioNewDirID should be set to the directory ID of the destination directory.It is usually simplest to specify the destination directory by passing its directory ID in the ioNewDirID field and by setting ioNewName to NIL.<36pt\>\x12 <8bat\>uIf a file ID reference exists for the file, the file ID reference remains with the moved file.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeioErr    –36    I/O errorbdNamErr    –37    Bad filename or attempt to move into a filefnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockdupFNErr    –48    Duplicate filename and versionparamErr    –50    No default volumebadMovErr    –122    Attempt to move into offspringMaintaining Working DirectoriesThe File Manager provides several low-level functions that allow you to manipulate working directories. Working directories are used internally by the File Manager; in general, your application should not create or directly access working directories.2PBOpenWDYou can use the PBOpenWD function to create a working directory.FUNCTION PBOpenWD (paramBlock: WDPBPtr; async: Boolean): OSErr;paramBlock    A pointer to a working directory parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr     StringPtr    A pointer to a pathname.´     ioVRefNum    Integer    A volume specification.Æ     ioWDProcID    LongInt    The working directory user identifier.Æ     ioWDDirID    LongInt    The working directory’s directory ID.DESCRIPTIONPBOpenWD takes the directory specified by ioVRefNum, ioWDDirID, and ioWDProcID and makes it a working directory. (You can also specify the directory using a combination of partial pathname and directory ID.) PBOpenWD returns a working directory reference number in ioVRefNum that can be used in subsequent calls.If a given directory has already been made a working directory using the same ioWDProcID, no new working directory is opened; instead, the existing working directory reference number is returned. If a given directory was already made a working directory using a different ioWDProcID, a new working directory reference number is returned.RESULT CODESnoErr    0    No errortmwdoErr    –121    Too many working directories open2PBCloseWDYou can use the PBCloseWD function to close a working directory.FUNCTION PBCloseWD (paramBlock: WDPBPtr; async: Boolean): OSErr;paramBlock    A pointer to a working directory parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioVRefNum    Integer    A working directory reference number.DESCRIPTIONPBCloseWD releases the working directory whose working directory reference number is specified in ioVRefNum.If you specify a volume reference number in the ioVRefNum field, PBCloseWD does nothing.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errornsvErr    –35    No such volume2PBGetWDInfoYou can use the PBGetWDInfo function to get information about a working directory.FUNCTION PBGetWDInfo (paramBlock: WDPBPtr; async: Boolean): OSErr;paramBlock    A pointer to a working directory parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.¨     ioNamePtr     StringPtr    A pointer to a pathname.´     ioVRefNum    Integer    A volume specification.Æ     ioWDIndex    Integer    An index.´     ioWDProcID    LongInt    The working directory user identifier.´     ioWDVRefNum    Integer    The volume reference number for the working directory.¨     ioWDDirID    LongInt    The working directory’s directory ID.DESCRIPTIONPBGetWDInfo returns information about the specified working directory. The working directory can be specified either by its working directory reference number in ioVRefNum (in which case ioWDIndex should be 0), or by its index number in ioWDIndex. In the latter case, if ioVRefNum is nonzero, it’s interpreted as a volume specification, and only working directories on that volume are indexed.The ioWDVRefNum field always returns the volume reference number. The ioVRefNum field returns a working directory reference number when a working directory reference number is passed in that field; otherwise, it returns a volume reference number. The volume name is returned in ioNamePtr. If ioWDProcID is nonzero, only working directories with that identifier are indexed; otherwise all working directories are indexed.RESULT CODESnoErr    0    No errornsvErr    –35    No such volumeSearching a CatalogThe low-level HFS function PBCatSearch allows you to search a volume using a particular set of search criteria.2PBCatSearchThe PBCatSearch function searches a volume’s catalog using a set of search criteria that you specify. It builds a list of all files or directories that meet your specifications.FUNCTION PBCatSearch (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to an HFS parameter block of type csParam.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a volume name.Æ     ioVRefNum    Integer    A volume specification.Æ     ioMatchPtr    FSSpecArrayPtr    A pointer to an array of matches.Æ     ioReqMatchCount    LongInt    The maximum match count.¨     ioActMatchCount    LongInt    The actual match count.Æ     ioSearchBits    LongInt    Enable bits for fields in criteria records.Æ     ioSearchInfo1    CInfoPBPtr    The values and lower bounds.Æ     ioSearchInfo2    CInfoPBPtr    The masks and upper bounds.Æ     ioSearchTime    LongInt    The maximum allowed search time.Æ     ioCatPosition    CatPositionRec    The current catalog position.Æ     ioOptBuffer    Ptr    A pointer to optional read buffer.Æ     ioOptBufSize    LongInt    The length of optional read buffer.DESCRIPTIONPBCatSearch searches the volume you specify for files or directories that match two coordinated sets of selection criteria. PBCatSearch returns (in the ioMatchPtr field) a pointer to an array of FSSpec records identifying the files and directories that match the criteria.If the catalog changes between two timed calls to PBCatSearch (that is, when you are using ioSearchTime and ioCatPosition to search a volume in segments and the catalog changes between searches), PBCatSearch returns a result code of catalogChangedErr. Depending on what has changed on the volume, ioCatPosition might be invalid, most likely by a few entries in one direction or another. You can continue the search, but you risk either skipping some entries or reading some twice.When PBCatSearch has searched the entire catalog, it returns eofErr. If it exits because it either spends the maximum time allowed by ioSearchTime or finds the maximum number of matches allowed by ioReqMatchCount, it returns noErr. You can specify a value of 0 in the ioSearchTime field to indicate that no time limit is to be enforced.SPECIAL CONSIDERATIONSNot all volumes support the PBCatSearch function. Before you call PBCatSearch to search a particular volume, you should call the PBHGetVolParms function to determine whether that volume supports PBCatSearch.RESULT CODESnoErr    0    No error (entire catalog has not been searched)nsvErr    –35    Volume not foundioErr    –36    I/O erroreofErr    –39    Logical end-of-file reachedparamErr    –50    Parameters don’t specify an existing volumeextFSErr    –58    External file systemcatalogChangedErr    –1304    Catalog has changed and catalog position        record may be invalidSEE ALSOSee  “Searching a Catalog” on page 2-32 for a description of how to use PBCatSearch.Exchanging the Data in Two FilesThe  low-level HFS function PBExchangeFiles allows you to exchange the data in two files.2PBExchangeFilesYou can use the PBExchangeFiles function to exchange the data stored in two files on the same volume.FUNCTION PBExchangeFiles (paramBlock: HParmBlkPtr;                                     async: Boolean): OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioDestNamePtr    StringPtr    A pointer to the name of the destination file.Æ     ioDestDirID    LongInt    The destination file’s parent directory ID.Æ     ioSrcDirID    LongInt    The source file’s parent directory ID.DESCRIPTIONPBExchangeFiles swaps the data in two files by changing some of the information in the volume catalog and, if the files are open, in the file control blocks. The PBExchangeFiles function uses the file ID parameter block.You should use PBExchangeFiles to preserve the file ID when updating an existing file, in case the file is being tracked through its file ID.Typically, you use PBExchangeFiles after creating a new file during a safe save. You identify the names and parent directory IDs of the two files to be exchanged in the fields ioNamePtr, ioDestNamePtr, ioSrcDirID, and ioDestDirID. PBExchangeFiles changes the fields in the catalog entries that record the location of the data and the modification dates. It swaps both the data forks and the resource forks.PBExchangeFiles works on either open or closed files. If either file is open, PBExchangeFiles updates any file control blocks associated with the file. Exchanging the contents of two files requires essentially the same access privileges as opening both files for writing.PBExchangeFiles does not require that file ID references exist for the files being exchanged.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundioErr    –36    I/O errorfnfErr    –43    File not foundfLckdErr    –45    File lockedvolOfflinErr    –53    Volume is off linewrgVolTypeErr    –123    Not an HFS volumediffVolErr    –1303    Files on different volumesShared Environment RoutinesThe File Manager provides a number of routines that allow you to control access to files, directories, and volumes in a shared environment. The routines described in this section allow you ton    provide multiple users with read/write access to filesn    lock and unlock portions of files opened with shared read/write permissionn    manipulate share points on local shared volumesn    get and change the access privileges for directoriesn    mount remote volumesn    control login accessBefore using the routines described in this section, call the PBHGetVolParms function to see if the volume supports them. (The PBGetVolMountInfoSize, PBGetVolMountInfo, and PBVolumeMount routines are exceptions: you’ll just have to make these calls and check the result code.)Opening Files While Denying AccessThe PBHOpenDeny and PBHOpenRFDeny functions control file access modes and enable applications to implement shared read/write access to files.2PBHOpenDenyYou can use the PBHOpenDeny function to open a file’s data fork using the access deny modes.FUNCTION PBHOpenDeny (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.¨     ioRefNum    Integer    The file reference number.Æ     ioDenyModes    Integer    Access rights data.Æ     ioDirID    LongInt    The directory ID.DESCRIPTIONPBHOpenDeny opens a file’s data fork with specific access rights specified in the ioDenyModes field. The file reference number is returned in ioRefNum.The result code opWrErr is returned if you’ve requested write permission and the file is already opened by you for writing; in that case, the existing file reference number is returned in ioRefNum. You should ignore that number.RESULT CODESnoErr    0    No errorfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr     –54    File is already open and cannot be opened using        specified deny modesafpAccessDenied    –5000    User does not have the correct access to the file2PBHOpenRFDenyYou can use the PBHOpenRFDeny function to open a file’s resource fork using the access deny modes.FUNCTION PBHOpenRFDeny (paramBlock: HParmBlkPtr;                                 async: Boolean): OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.¨     ioRefNum    Integer    The file reference number.Æ     ioDenyModes    Integer    Access rights data.Æ     ioDirID    LongInt    The directory ID.DESCRIPTIONPBHOpenRFDeny opens a file’s resource fork with specific access rights. The path reference number is returned in ioRefNum.The result code opWrErr is returned if you’ve requested write permission and the file is already opened by you for writing; in that case, the existing file reference number is returned in ioRefNum. You should ignore that number.RESULT CODESnoErr    0    No errorfnfErr    –43    File not foundopWrErr    –49    File already open for writingpermErr     –54    File is already open and cannot be opened using        specified deny modesafpAccessDenied    –5000    User does not have the correct access to the fileLocking and Unlocking File RangesThe File Manager provides several low-level routines that allow you to lock and unlock parts of files. These functions are ineffective when used on local HFS volumes unless local file sharing is enabled for those volumes.2PBLockRangeYou can use the PBLockRange function to lock a portion of a file.FUNCTION PBLockRange (paramBlock: ParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.Æ     ioReqCount    LongInt    The number of bytes in the range.Æ     ioPosMode    Integer    The positioning mode.Æ     ioPosOffset    LongInt    The positioning offset.DESCRIPTIONPBLockRange locks a portion of a file that was opened with shared read/write permission. The beginning of the range to be locked is determined by the ioPosMode and ioPosOffset fields. The end of the range to be locked is determined by the beginning of the range and the ioReqCount field. For example, to lock the first 50 bytes in a file, set ioReqCount to 50, ioPosMode to fsFromStart, and ioPosOffset to 0.PBLockRange uses the same parameters as both PBRead and PBWrite; by calling it immediately before PBRead, you can use the information in the parameter block for the PBRead call.When you’re finished with the data (typically after a call to PBWrite), be sure to call PBUnlockRange to free that portion of the file for subsequent PBRead calls.SPECIAL CONSIDERATIONSPBLockRange does nothing if the file specified in the ioRefNum field is open with shared read/write permission but is not located on a remote server volume or is not located under a share point on a local volume. See “Locking and Unlocking File Ranges” for a simple way to determine whether calling PBLockRange on an open file would in fact lock a range of bytes.In system software versions 6.0.7 and earlier, specifying ioPosMode as fsFromLEOF results in the wrong byte range being locked.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openeofErr    –39    End-of-fileparamErr    –50    Negative ioReqCountrfNumErr    –51    Bad reference numberextFSErr    –58    External file system2PBUnlockRangeYou can use the PBUnlockRange function to unlock a portion of a file that was previously locked using PBLockRange.FUNCTION PBUnlockRange (paramBlock: ParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a basic parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioRefNum    Integer    A file reference number.Æ     ioReqCount    LongInt    The number of bytes in the range.Æ     ioPosMode    Integer    The positioning mode.Æ     ioPosOffset    LongInt    The positioning offset.DESCRIPTIONPBUnlockRange unlocks a portion of a file that you locked with PBLockRange. You specify the range by filling in the ioReqCount, ioPosMode, and ioPosOffset fields as described in the previous section. The range of bytes to be unlocked must be the exact same range locked by a previous call to PBLockRange.If for some reason you need to unlock a range whose beginning or length are unknown, you can simply close the file. When a file is closed, all locked ranges held by the user are unlocked.SPECIAL CONSIDERATIONSPBUnlockRange does nothing if the file specified in the ioRefNum field is open with shared read/write permission but is not located on a remote server volume or is not located under a share point on a local volume.RESULT CODESnoErr    0    No errorioErr    –36    I/O errorfnOpnErr    –38    File not openeofErr    –39    End-of-fileparamErr    –50    Negative ioReqCountrfNumErr    –51    Bad reference numberextFSErr    –58    External file systemManipulating Share PointsThe PBShare and PBUnshare functions allow you to manipulate share points on local volumes. The PBGetUGEntry function lets you create a list of user and group names and IDs on the local server. 2PBShareYou can use the PBShare function to establish a local volume or directory as a share point.FUNCTION PBShare (paramBlock: HParmBlkPtr; async: Boolean): OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioDirID    LongInt    A directory ID.DESCRIPTIONPBShare makes the directory specified by the ioNamePtr and ioDirID fields a share point. If ioNamePtr is NIL, then ioDirID is the directory ID of the directory that is to become a share point. If ioNamePtr points to a partial pathname, ioDirID is the parent directory of the directory to be shared. The ioVRefNum field can contain a volume reference number, a working directory reference number, a drive number, or 0 for the default volume.RESULT CODESnoErr    0    No errortmfoErr    –42    Too many share pointsfnfErr    –43    File not founddupFNErr    –48    Already a share point with this nameparamErr    –50    Function not supporteddirNFErr    –120    Directory not foundafpAccessDenied    –5000    This directory cannot be sharedafpObjectTypeErr    –5025    Object was a file, not a directoryafpContainsSharedErr    –5033    The directory contains a share pointafpInsideSharedErr    –5043    The directory is inside a shared directory2PBUnshareYou can use the PBUnshare function to reverse the effects of PBShare.FUNCTION PBUnShare (paramBlock: HParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioDirID    LongInt    A directory ID.DESCRIPTIONPBUnshare makes the share point specified by the ioNamePtr and ioDirID fields unavailable on the network. If ioNamePtr is NIL, then ioDirID is the directory ID of the directory that is to become unavailable. If ioNamePtr points to a partial pathname, ioDirID is the parent directory of the directory to become unavailable. The ioVRefNum field can contain a volume reference number, a working directory reference number, a drive number, or 0 for the default volume.RESULT CODESnoErr    0    No errorfnfErr    –43    File not founddirNFErr    –120    Directory not foundafpObjectTypeErr    –5025    Object was a file, not a directory; or, this        directory is not a share point2PBGetUGEntryYou can use the PBGetUGEntry function to get a list of user and group entries from the local file server.FUNCTION PBGetUGEntry (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to an HFS parameter block of type objParam.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioObjType    Integer    A function code.Æ     ioObjNamePtr    Ptr    A pointer to the returned user/group name.´    ioObjID    LongInt    A user/group ID.DESCRIPTIONPBGetUGEntry returns the name and ID of the user or group whose name is alphabetically next from the user or group whose ID is contained in the ioObjID field. You can enumerate the users or groups in alphabetical order by setting ioObjID to 0 and then repetitively calling PBGetUGEntry with the same parameter block until the result code fnfErr is returned.You specify whether you want information about users, groups, or both by setting the ioObjType field to the desired value. Set ioObjType to 1 to receive the next user entry, 2 to receive the next group entry, or 3 to receive the next user or group entry.The user or group name is returned as a Pascal string pointed to by ioObjNamePtr. If you set ioObjNamePtr to NIL, no name is returned.If you set ioObjID to 0, PBGetUGEntry returns information about the user or group known to the local server whose name is alphabetically first. If ioObjID is non-zero, PBGetUGEntry returns information about the user or group whose name alphabetically follows the user or group having that ID.RESULT CODESnoErr    0    No errorfnfErr    –43    No more users or groupsparamErr    –50    Function not supported; or, ioObjID is negativeControlling Directory AccessThe PBHGetDirAccess and PBHSetDirAccess functions control privileges for individual directories.2PBHGetDirAccessYou can use the PBHGetDirAccess function to get the access control information for a directory.FUNCTION PBHGetDirAccess (paramBlock: HParmBlkPtr;                                     async: Boolean): OSErr;paramBlock    A pointer to an HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.¨     ioACOwnerID    LongInt    The owner ID.¨     ioACGroupID    LongInt    The group ID.¨     ioACAccess    LongInt    The access rights.Æ     ioDirID    LongInt    The directory ID.DESCRIPTIONPBHGetDirAccess returns access control information for the specified directory. On output, the ioACOwnerID field contains the ID of the directory’s owner and the ioACGroupID field contains the directory’s primary group. The directory’s access rights are encoded in the ioACAccess field.RESULT CODESnoErr    0    No errorfnfErr    –43    Directory not foundafpAccessDenied    –5000    User does not have the correct access to the        directory2PBHSetDirAccessYou can use the PBHSetDirAccess function to change the access control information for a directory.FUNCTION PBHSetDirAccess (paramBlock: HParmBlkPtr;                                     async: Boolean): OSErr;paramBlock    A pointer to an HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioACOwnerID    LongInt    The owner ID.Æ     ioACGroupID    LongInt    The group ID.Æ     ioACAccess    LongInt    The access rights.Æ     ioDirID    LongInt    The directory ID.DESCRIPTIONPBHSetDirAccess allows you to change the access rights to the specified directory. The ioACAccess field contains the directory’s access rights. You cannot set the owner or user rights bits of the ioACAccess field directly (if you try to do this, PBHSetDirAccess returns the result code paramErr). To change the owner or group, you should set the ioACOwnerID or ioACGroupID field with the appropriate ID. You must be the owner of the directory to change the owner or group ID.RESULT CODESnoErr    0    No errorfnfErr    –43    Directory not foundparamErr    –50    Parameter errorafpAccessDenied    –5000    User does not have the correct access to the        directoryMounting VolumesThe File Manager provides three functions that allow your application to record the mounting information for a volume and then to mount the volume later. The programmatic mounting functions store the mounting information in a structure called the AFPVolMountInfo record.The programmatic mounting functions use the ioParam variant of the ParamBlockRec record.2PBGetVolMountInfoSizeYou use the PBGetVolMountInfoSize function to determine how much space to allocate for a volume mounting information record.FUNCTION PBGetVolMountInfoSize (paramBlock: ParmBlkPtr): OSErr;paramBlock    A pointer to a basic parameter block.Æ     ioCompletion    LongInt    A pointer to a completion routine.¨     ioResult    OSErr    The function’s result code.Æ    ioVRefNum    Integer    A volume specification.Æ    ioBuffer    LongInt    A pointer to storage for size.DESCRIPTIONFor a specified volume, the PBGetVolMountInfoSize function provides the size of the record needed to hold the volume’s mounting information. The ioBuffer field is a pointer to the size information, which is of type Integer (2 bytes). If PBGetVolMountInfoSize returns noErr, that integer contains the size of the volume mounting information record.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundparamErr    –50    Parameter errorextFSErr    –58    External file system error; typically,         function is not available for that volume2PBGetVolMountInfoAfter ascertaining the size of the record needed and allocating storage, you can use the PBGetVolMountInfo function to retrieve a record containing all the information needed to mount the volume, except for passwords. You can later pass this record to the PBVolumeMount function to mount the volume.FUNCTION PBGetVolMountInfo (paramBlock: ParmBlkPtr): OSErr;paramBlock    A pointer to a basic parameter block.Æ    ioCompletion    LongInt    A pointer to a completion routine.¨    ioResult    OSErr    The function’s result code.Æ    ioVRefNum    Integer    A volume specification.Æ    ioBuffer    LongInt    A pointer to mounting information.DESCRIPTIONPBGetVolMountInfo places the mounting information for a specified volume into the buffer pointed to by the ioBuffer field. The mounting information for an AppleShare volume is stored as an AFP mounting record. The length of the buffer is specified by the value pointed to by the ioBuffer field in a previous call to PBGetVolMountInfoSize.PBGetVolMountInfo does not return the user password or volume password in the AFPVolMountInfo record. Your application should solicit these passwords from the user and fill in the record before attempting to mount the remote volume.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundparamErr    –50    Parameter errorextFSErr    –58    External file system error; typically, function is        not available for that volume2PBVolumeMountYou can use the PBVolumeMount function to mount a volume, using either the information returned by the PBGetVolMountInfo function or a structure filled in by your application.FUNCTION PBVolumeMount (paramBlock: ParmBlkPtr): OSErr;paramBlock    A pointer to a basic File Manager parameter block.Æ     ioCompletion    LongInt    A pointer to a completion routine.¨     ioResult    OSErr    The function’s result code.¨    ioVRefNum    Integer    A volume reference number.Æ     ioBuffer    LongInt    A pointer to mounting information.DESCRIPTIONThe PBVolumeMount function mounts a volume and returns its volume reference number. If you’re mounting an AppleShare volume, place the volume’s AFP mounting information record in the buffer pointed to by the ioBuffer field. PBGetVolMountInfo does not return the user and volume passwords; they’re returned as blank. Typically, your application asks the user for any necessary passwords and fills in those fields just before calling PBVolumeMount. No passwords are required for mounting a volume with guest status.If you have enough information about the volume, you can fill in the mounting record yourself and call PBVolumeMount, even if you did not save the mounting information while the volume was mounted. To mount an AFP volume, you must fill in the record with at least the zone name, server name, user name, user password, and volume password. You can lay out the fields in any order within the data field, as long as you specify the correct offsets.RESULT CODESnoErr    0    No errornotOpenErr    –28    AppleTalk is not opennsvErr    –35    Volume not foundparamErr    –50    Parameter error; typically, zone, server, and        volume name combination is not valid or not        complete, or the user name is not recognizedextFSErr    –58    External file system error; typically, file system         signature was not recognized, or function is not         available for that volumememFullErr    –108    Not enough memory to create a new volume         control block for mounting the volumeafpBadUAM    –5002    User authentication method is unknownafpBadVersNum    –5003    Workstation is using an AFP version that the         server doesn’t recognizeafpNoServer    –5016    Server is not respondingafpUserNotAuth    –5023    User authentication failed (usually, password is         not correct)afpPwdExpired    –5042    Password has expired on serverafpBadDirIDType    –5060    Not a fixed directory ID volumeafpCantMountMoreSrvrs    –5061    Maximum number of volumes has been         mountedafpAlreadyMounted    –5062    Volume already mountedafpSameNodeErr    –5063    Attempt to log on to a server running on the         same machineControlling Login AccessYou can use the functions PBHGetLogInInfo, PBHMapID, and PBHMapName to get information about the login method and the recognized users and groups on a particular machine.2PBGetLogInInfoYou can use the PBGetLogInInfo function to determine the login method supported by a particular shared volume.FUNCTION PBHGetLogInInfo (paramBlock: HParmBlkPtr;                                     async: Boolean): OSErr;paramBlock    A pointer to an HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.PARAMETER BLOCKÆ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioVRefNum    Integer    The volume specification.¨     ioObjType    Integer    The login method.¨     ioObjNamePtr    Ptr    A pointer to the creator/group name.DESCRIPTIONPBHGetLogInInfo returns the method used for login and the user name specified at login time for the volume specified by the ioVRefNum field. The login user name is returned as a Pascal string in ioObjNamePtr. The maximum size of the user name is 31 characters.  The login method type is returned in the ioObjType field. These values are recognized.kNoUserAuthentication                                            =    1;    {guest status; no password needed}kPassword                                            =    2;    {8-byte password}kEncryptPassword                                            =    3;    {encrypted 8-byte password}kTwoWayEncryptPassword                                            =    6;    {two-way random encryption; }                                                    { authenticate both user and server}Values in the range 7–127 are reserved for future use by Apple. Values in the range 128–255 are available to your application as user-defined values.RESULT CODESnoErr    0    No errornsvErr    –35    Specified volume doesn’t exist2PBHMapIDYou can use the PBHMapID function to determine the name of a user or group if you know the user or group ID.FUNCTION PBHMapID (paramBlock: HParmBlkPtr; async: Boolean):                            OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.PARAMETER BLOCKÆ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioObjType    Integer    The login method.¨     ioObjNamePtr    Ptr    A pointer to the owner/group name.Æ     ioObjID    LongInt    The owner/group ID.DESCRIPTIONPBHMapID returns the name of a user or group given its unique ID.  The ioObjID field contains the ID to be mapped.  (AppleShare use the value 0 to signify <Any User>.) The ioObjType is the mapping function code; it’s 1 if you’re mapping an owner ID to owner name, or 2 if you’re mapping a group ID to a group name.  The name is returned in ioObjNamePtr; the maximum size of the name is 31 characters (preceded by a length byte).RESULT CODESnoErr    0    No errorfnfErr    –43    Unrecognizable owner or group name2PBHMapNameYou can use the PBHMapName function to determine the user ID or group ID from a user or group name.FUNCTION PBHMapName (paramBlock: HParmBlkPtr; async: Boolean):                             OSErr;paramBlock    A pointer to a basic HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.PARAMETER BLOCKÆ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioObjType    Integer    The login method.Æ     ioObjNamePtr    Ptr    A pointer to the owner/group name.¨     ioObjID    LongInt    The owner/group ID.DESCRIPTIONPBHMapName returns the unique user ID or group ID given its name.  The name is passed as a string in ioObjNamePtr.  If a NIL name is passed, the ID returned will always be zero.  The maximum size of the name is 31 characters.  The ObjType field is the mapping function code; it’s 3 if you’re mapping an owner name to owner ID, or 4 if you’re mapping a group name to a group ID.  On exit, ioObjID contains the mapped ID.RESULT CODESnoErr    0    No errorfnfErr    –43    Unrecognizable owner or group nameCopying and Moving FilesThe File Manager provides two shared environment routines—PBHCopyFile and PBHMoveRename—that allow you to copy and move files. These routines are especially useful when you want to copy or move files located on a remote volume, because they allow you to forego transmitting large amounts of data across a network. These routines are used internally by the Finder; most applications do not need to use them.If you do want to use PBHCopyFile or PBHMoveRename, you should first call PBHGetVolParms to see whether the target volume supports these routines.2PBHCopyFileYou can use the PBHCopyFile function to duplicate a file and optionally to rename it.FUNCTION PBHCopyFile (paramBlock: HParmBlkPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a copyParam variant of the HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioDstVRefNum    Integer    Destination volume identifier.Æ     ioNewName    Ptr    A pointer to the destination pathname.Æ     ioCopyName    Ptr    A pointer to the file’s new name (may be NIL).Æ     ioNewDirID    LongInt    The destination directory ID.Æ     ioDirID    LongInt    The source directory ID.DESCRIPTIONPBHCopyFile duplicates a file on the specified volume and optionally renames it. It is an optional call for AppleShare file servers. Your application should examine the information returned by the PBHGetVolParms function to see if the volume supports PBHCopyFile.For AppleShare file servers, the source and destination pathnames must indicate the same file server; however, the parameter block may specify different source and destination volumes on that file server. A useful way to tell if two file server volumes are on the same file server is to call the PBHGetVolParms function for each volume and compare the server addresses returned. The server will open source files with read/deny write enabled and destination files with write/deny read and write enabled.The ioVRefNum field contains a source volume identifier. The source pathname is determined by the ioNamePtr and ioDirID fields. The ioDstVRefNum field contains a destination volume identifier; this identifier can be a working directory reference number. The destination pathname is determined by the ioNewName and ioNewDirID fields. The ioCopyName field may contain an optional string used in renaming the file; if it is not NIL, the file copy will be renamed to the name specified in ioCopyName.RESULT CODESnoErr    0    No errorfnfErr    –43    Source file not found, or destination directory        does not existdupFNErr     –48    Destination file already existsafpAccessDenied    –5000    The user does not have the right to read the        source or write to the destinationafpDenyConflict    –5006    The source or destination file could not be        opened with the correct access modes 2PBHMoveRenameYou can use the PBHMoveRename function to move a file or directory and optionally to rename it.FUNCTION PBHMoveRename (paramBlock: HParmBlkPtr;                                 async: Boolean): OSErr;paramBlock    A pointer to a copyParam variant of the HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.Æ     ioNewName    Ptr    A pointer to the destination pathname.Æ     ioBuffer    Ptr    A pointer to the file’s new name (may be NIL).Æ     ioNewDirID    LongInt    The destination directory ID.Æ     ioDirID    LongInt    The source directory ID.DESCRIPTIONPBHMoveRename allows you to move (not copy) a file or directory and optionally to rename it. The source and destination pathnames must point to the same file server volume.The ioVRefNum field contains a source volume identifier. The source pathname is specified by the ioNamePtr and ioDirID fields. The destination pathname is specified by the ioNewName and ioNewDirID fields. The ioBuffer field may contain an optional string used in renaming the file or directory; if it is not NIL, the moved object will be renamed to the name specified in ioBuffer.RESULT CODESnoErr    0    No errorfnfErr    –43    Source file or directory not founddupFNErr     –48    Destination already existsbadMovErr    –122    Attempted to move directory into offspringafpAccessDenied    –5000    The user does not have the right to move the        file or directory File ID RoutinesThe File Manager provides several routines that allow you to track files using file IDs. These routines use the fidParam variant of the HFS parameter block.Most applications do not need to use these routines. In general you should track files using alias records, as described in the Alias Manager chapter in this volume. The Alias Manager uses file IDs internally as part of its search algorithms for finding the target of an alias record.<36pt\>\x12 <8bat\>uResolving File ID ReferencesYou can find the target of a file ID reference by calling the PBResolveFileIDRef function.2PBResolveFileIDRefYou can use the PBResolveFileIDRef function to retrieve the filename and parent directory ID of the file with a specified file ID.FUNCTION PBResolveFileIDRef (paramBlock: HParmBlkPtr;                                         async: Boolean): OSErr;paramBlock    A pointer to an HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ    ioCompletion    ProcPtr    A pointer to completion routine.¨    ioResult    OSErr    The result code of the function.´    ioNamePtr    StringPtr    A pointer to a filename.Æ     ioVRefNum    Integer    A volume specification.¨    ioSrcDirID    LongInt    The file’s parent directory ID.Æ    ioFileID    LongInt    A file ID.DESCRIPTIONPBResolveFileIDRef returns the filename and parent directory ID of the file referred to by file ID in the ioFileID field. It places the filename in the string pointed to by the ioNamePtr field and the parent directory ID in the ioSrcDirID field. If the name string is NIL, PBResolveFileIDRef returns only the parent directory ID. If the name string is not NIL but is only a volume name, PBResolveFileIDRef ignores the value in the ioVRefNum field, uses the volume name instead, and overwrites the name string with the filename. A return code of fidNotFoundErr means that the specified file ID reference has become invalid, either because the file was deleted or because the file ID reference was destroyed by PBDeleteFileIDRef.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundioErr    –36    I/O errorfnfErr    –43    File not foundvolOfflinErr    –53    Volume is off lineextFSErr    –58    External file systemwrgVolTypeErr    –123    Not an HFS volumefidNotFoundErr    –1300    File ID not foundnotAFileErr    –1302    Specified file is a directoryCreating and Deleting File ID ReferencesYou can create and delete file ID references using the functions PBCreateFileIDRef and PBDeleteFileIDRef.Most applications should not directly create or delete file ID references.<36pt\>\x12 <8bat\>u2PBCreateFileIDRefUse the PBCreateFileIDRef function to establish a file ID reference for a file.FUNCTION PBCreateFileIDRef (paramBlock: HParmBlkPtr;                                         async: Boolean): OSErr;paramBlock    A pointer to an HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Parameter blockÆ    ioCompletion    ProcPtr    A pointer to a completion routine.¨    ioResult    OSErr    The result code of the function.Æ    ioNamePtr    StringPtr    A pointer to a filename.Æ    ioVRefNum    Integer    A volume specification.Æ    ioSrcDirID    LongInt    The file’s parent directory ID.¨    ioFileID    LongInt    A file ID.DESCRIPTIONGiven a volume reference number, filename, and parent directory ID, PBCreateFileIDRef creates a record to hold the name and parent directory ID of the specified file. PBCreateFileIDRef places the file ID in the ioFileID field. If a file ID reference already exists for the file, PBCreateFileIDRef supplies the file ID but returns the result code fidExists.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundioErr    –36    I/O errorfnfErr    –43    File not foundwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockvolOfflinErr    –53    Volume is off lineextFSErr    –58    External file systemwrgVolTypeErr    –123    Not an HFS volumefidExists    –1301    File ID already existsnotAFileErr    –1302    Specified file is a directory2PBDeleteFileIDRefYou can use the PBDeleteFileIDRef function to delete a file ID reference.FUNCTION PBDeleteFileIDRef (paramBlock: HParmBlkPtr;                                         async: Boolean): OSErr;paramBlock    A pointer to an HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ    ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ    ioNamePtr    StringPtr    A pointer to a filename.Æ    ioVRefNum    Integer    A volume specification.Æ     ioFileID    LongInt    A file ID.DESCRIPTIONPBDeleteFileIDRef invalidates the specified file ID reference on the volume specified by ioVRefNum or ioNamePtr. After it has invalidated a file ID reference, the File Manager can no longer resolve that ID reference to a filename and parent directory ID.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundioErr    –36    I/O errorwPrErr    –44    Hardware volume lockvLckdErr    –46    Software volume lockvolOfflinErr    –53    Volume is off lineextFSErr    –58    External file systemfidNotFoundErr    –1300    File ID not foundForeign File System RoutinesThe File Manager provides several routines that allow you to obtain and set privilege information on foreign file systems.Accessing Privilege Information in Foreign File SystemsThe PBGetForeignPrivs and PBSetForeignPrivs functions allow your application or shell program to communicate with a foreign file system about its native access-control system. These functions retrieve and set access permissions on the foreign file system, using a parameter block of type foreignPrivParam. 2PBGetForeignPrivsYou can use the PBGetForeignPrivs function to determine the native access-control information for a file or directory stored on a volume managed by a foreign file system.FUNCTION PBGetForeignPrivs (paramBlock: HParmBlkPtr;                                         async: Boolean): OSErr;paramBlock    A pointer to an HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to file or directory name.¨     ioVRefNum    Integer    A volume specification.¨     ioForeignPrivBuffer    Ptr    A pointer to the privilege info buffer.Æ     ioForeignPrivReqCount    LongInt    The size allocated for the buffer.¨     ioForeignPrivActCount    LongInt    The amount used in buffer.Æ     ioForeignPrivDirID    Integer    The parent directory ID.¨     ioForeignPrivInfo1    LongInt    Information specific to privilege model.¨     ioForeignPrivInfo2    LongInt    Information specific to privilege model.¨     ioForeignPrivInfo3    LongInt    Information specific to privilege model.¨     ioForeignPrivInfo4    LongInt    Information specific to privilege model.DESCRIPTIONPBGetForeignPrivs retrieves access information for a file or directory on a volume managed by a file system that uses a privilege model different from the AFP model. See “Privilege Information in Foreign File Systems” on page 2-17 for a fuller explanation of access-control privileges.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundparamErr    –50    Volume is HFS or MFS (that is, it has no foreign        privilege model), or foreign volume does not        support these calls2PBSetForeignPrivsYou can use the PBSetForeignPrivs function to change the native access-control information for a file or directory stored on a volume managed by a foreign file system.FUNCTION PBSetForeignPrivs (paramBlock: HParmBlkPtr;                                         async: Boolean): OSErr;paramBlock    A pointer to an HFS parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.Æ     ioNamePtr    StringPtr    A pointer to file or directory name.Æ     ioVRefNum    Integer    A volume specification.Æ     ioForeignPrivBuffer    Ptr    A pointer to the privilege info buffer.Æ     ioForeignPrivReqCount    LongInt    The size allocated for the buffer.Æ     ioForeignPrivActCount    LongInt    The amount used in buffer.Æ     ioForeignPrivDirID    Integer    The parent directory ID.Æ     ioForeignPrivInfo1    LongInt    Information specific to privilege model.Æ    ioForeignPrivInfo2    LongInt    Information specific to privilege model.Æ     ioForeignPrivInfo3    LongInt    Information specific to privilege model.Æ     ioForeignPrivInfo4    LongInt    Information specific to privilege model.DESCRIPTIONPBSetForeignPrivs modifies access information for a file or directory on a volume managed by a file system that uses a privilege model different from the AFP model.RESULT CODESnoErr    0    No errornsvErr    –35    Volume not foundparamErr    –50    Volume is HFS or MFS (that is, it has no foreign        privilege model), or foreign volume does not        support these callsUtility RoutinesThe File Manager provides several utility routines that allow you to obtain information about File Manager queues and file control blocks. These routines insulate your application from the need to know about the data structures maintained internally by the File Manager. Most applications do not need to use these routines.Obtaining Queue HeadersYou can use the functions GetFSQHdr, GetVCBQHdr, and GetDrvQHdr to obtain a pointer to the head of the file I/O queue, the VCB queue, and the drive queue, respectively. See the “Queue Utilities” chapter in this volume for a description of queues and the format of a queue header.2GetFSQHdrYou can use the GetFSQHdr function to get a pointer to the header of the file I/O queue.FUNCTION GetFSQHdr: QHdrPtr;DESCRIPTIONGetFSQHdr returns a pointer to the header of the file I/O queue.ASSEMBLY LANGUAGE INFORMATIONThe global variable FSQHdr contains the header of the file I/O queue.2GetVCBQHdrYou can use the GetVCBQHdr function to get a pointer to the header of the VCB queue.FUNCTION GetVCBQHdr: QHdrPtr;DESCRIPTIONGetVCBQHdr returns a pointer to the header of the VCB queue.ASSEMBLY LANGUAGE INFORMATIONThe global variable VCBQHdr contains the header of the VCB queue. The default volume’s volume control block is pointed to by the global variable DefVCBPtr.2GetDrvQHdrYou can use the GetDrvQHdr function to get a pointer to the header of the drive queue.FUNCTION GetDrvQHdr: QHdrPtr;DESCRIPTIONGetDrvQHdr returns a pointer to the header of the drive queue.ASSEMBLY LANGUAGE INFORMATIONThe global variable DrvQHdr contains the header of the drive queue.Adding a DriveThe AddDrive procedure allows you to add a drive.2AddDriveYou can use the AddDrive procedure to add a drive to the system.PROCEDURE AddDrive (drvrRefNum: Integer; drvNum: Integer;                             qEl: DrvQElPtr);drvrRefNum    A driver reference number.drvNum    A drive number.qEl    A pointer to a drive queue element.DESCRIPTIONThe AddDrive procedure adds a disk drive having the specified driver reference number and drive number to the system. The File Manager expands the drive queue by adding a copy of the queue element pointed to by the qEl parameter to the end of the existing queue.Obtaining File Control Block InformationYou can get information from the file control block (FCB) allocated for an open file by calling the function PBGetFCBInfo.2PBGetFCBInfoYou can use PBGetFCBInfo to get information about an open file.FUNCTION PBGetFCBInfo (paramBlock: FCBPBPtr; async: Boolean):                                 OSErr;paramBlock    A pointer to a file control block parameter block.async    A Boolean value that specifies asynchronous (TRUE) or synchronous    (FALSE) execution.Æ     ioCompletion    ProcPtr    A pointer to a completion routine.¨     ioResult    OSErr    The result code of the function.´     ioNamePtr    StringPtr    A pointer to a pathname.Æ     ioVRefNum    Integer    A volume specification.´     ioRefNum    Integer    The file reference number.Æ     ioFCBIndx    Integer    An index.¨     ioFCBFlNm    LongInt    The file ID.¨     ioFCBFlags    Integer    File status flags.¨     ioFCBStBlk    Integer    The first allocation block of the file.¨     ioFCBEOF    LongInt    The logical end-of-file.¨     ioFCBPLen    LongInt    The physical end-of-file.¨     ioFCBCrPs    LongInt    The position of the file mark.¨     ioFCBVRefNum    Integer    The volume reference number.¨     ioFCBClpSiz    LongInt    The file clump size.¨     ioFCBParID    LongInt    The parent directory ID.DESCRIPTIONPBGetFCBInfo returns information about the specified open file. If ioFCBIndx is positive, the File Manager returns information about the file whose index in the FCB buffer is ioFCBIndx and which is located on the volume specified by ioVRefNum (which may contain a drive number, volume reference number, or working directory reference number). If ioVRefNum is 0, all open files are indexed; otherwise, only open files on the specified volume are indexed.If ioFCBIndx is 0, the File Manager returns information about the file whose file reference number is specified by the ioRefNum field. If ioFCBIndx is positive, the ioRefNum field is ignored on input and contains the file reference number on output.If PBGetFCBInfo executes successfully, the ioNamePtr field contains the name of the specified open file. You should pass a pointer to a Str31 if you want that name returned. If you pass NIL in the ioNamePtr field, no filename is returned.The ioFCBFlags field returns status information about the specified open file. See “File Control Block Parameter Blocks” for a description of the meaning of the bits in this field.RESULT CODESnoErr    0    No errornsvErr    –35    Specified volume doesn’t existfnOpnErr    –38    File not openrfNumErr    –51    Reference number specifies non-existent access        pathSummary of the File ManagerConstantsCONST        {Gestalt constants}    gestaltFSAttr                        =    'fs  ';            {file system attributes selector}    gestaltFullExtFSDispatching                            =    0;            {exports HFSDispatch traps}    gestaltHasFSSpecCalls                            =    1;            {supports FSSpec records}    {directory IDs}    fsRtParID                        =    1;            {directory ID of root directory’s parent}    fsRtDirID                        =    2;            {directory ID of volume’s root directory}    {values for requesting file read/write permissions}    fsCurPerm                        =    0;            {exclusive read/write permission, if }                                            { available; otherwise exclusive read}    fsRdPerm                        =    1;            {read-only permission}    fsWrPerm                        =    2;            {exclusive write permission}    fsRdWrPerm                        =    3;            {exclusive read/write permission}    fsRdWrShPerm                        =    4;            {shared read/write permission}    {file mark positioning modes}    fsAtMark                        =    0;            {at current mark}    fsFromStart                        =    1;            {set mark relative to beginning of file}    fsFromLEOF                        =    2;            {set mark relative to logical end-of-file}    fsFromMark                        =    3;            {set mark relative to current mark}    rdVerify                        =    64;            {add to above for read-verify}    {values for ioSearchBits in PBCatSearch parameter block}    fsSBPartialName                        =    1;            {substring of name}    fsSBFullName                        =    2;            {full name}    fsSBFlAttrib                        =    4;            {directory flag; software lock flag}    fsSBNegate                        =    16384;            {reverse match status}    {for files only}    fsSBFlFndrInfo                        =    8;            {Finder file info}    fsSBFlLgLen                        =    32;            {data fork logical length}    fsSBFlPyLen                        =    64;            {data fork physical length}    fsSBFlRLgLen                        =    128;            {resource fork logical length}    fsSBFlRPyLen                        =    256;            {resource fork physical length}    fsSBFlCrDat                        =    512;            {file creation date}    fsSBFlMdDat                        =    1024;            {file modification date}    fsSBFlBkDat                        =    2048;            {file backup date}    fsSBFlXFndrInfo                        =    4096;            {more Finder file info}    fsSBFlParID                        =    8192;            {file's parent ID}    {for directories only}    fsSBDrUsrWds                        =    8;            {Finder directory info}    fsSBDrNmFls                        =    16;            {number of files in directory}    fsSBDrCrDat                        =    512;            {directory creation date}    fsSBDrMdDat                        =    1024;            {directory modification date}    fsSBDrBkDat                        =    2048;            {directory backup date}    fsSBDrFndrInfo                        =    4096;            {more Finder directory info}    fsSBDrParID                        =    8192;            {directory's parent ID}    {value of vMForeignPrivID in file attributes buffer}    fsUnixPriv                        =    1;            {A/UX privilege model}    {bit positions in vMAttrib field of GetVolParmsInfoBuffer}    bHasBlankAccessPrivileges                            =    4;            {volume supports inherited folder privs.}    bHasBtreeMgr                        =    5;            {reserved}    bHasFileIDs                        =    6;            {volume supports file ID functions}    bHasCatSearch                        =    7;            {volume supports PBCatSearch}    bHasUserGroupList                        =    8;            {volume supports AFP privileges}    bHasPersonalAccessPrivileges                            =    9;            {local file sharing is enabled}    bHasFolderLock                        =    10;            {volume’s root folder is locked}    bHasShortName                        =    11;            {volume supports shorter volume name}    bHasDesktopMgr                        =    12;            {volume supports Desktop Manager}    bHasMoveRename                        =    13;            {volume supports _MoveRename}    bHasCopyFile                        =    14;            {volume supports _CopyFile}    bHasOpenDeny                        =    15;            {volume supports shared access modes}    bHasExtFSVol                        =    16;            {volume is external file system volume}    bNoSysDir                        =    17;            {volume has no system directory}    bAccessCntl                        =    18;            {volume supports AFP access control}    bNoBootBlks                        =    19;            {volume is not a startup volume}    bNoDeskItems                        =    20;            {do not place objects on the desktop}    bNoSwitchTo                        =    25;            {do not switch launch to applications}    bTrshOffLine                        =    26;            {zoom volume when it is unmounted}    bNoLclSync                        =    27;            {don’t let Finder change mod. date}    bNoVNEdit                        =    28;            {lock volume name}    bNoMiniFndr                        =    29;            {reserved; always 1}    bLocalWList                        =    30;            {use shared volume handle for window list}    bLimitFCBs                        =    31;            {limit file control blocks}    {media type in remote mounting information}    AppleShareMediaType                            = 'afpm';                 {an AppleShare volume}    {user authentication methods in AFP remote mounting information}    kNoUserAuthentication                                =    1;    {guest status; no password needed}    kPassword                                =    2;    {8-byte password}    kEncryptPassword                                =    3;    {encrypted 8-byte password}    kTwoWayEncryptPassword                                =    6;    {two-way random encryption; }                                            { authenticate both user and server}Data TypesFile System Specification RecordTYPE FSSpec                             =                    {file system specification}    RECORD                vRefNum:                        Integer;                {volume reference number}        parID:                        LongInt;                {directory ID of parent directory}        name:                        Str63;                {filename or directory name}    END;    FSSpecPtr                        =     ^FSSpec;    FSSpecHandle                        =     ^FSSpecPtr;    FSSpecArray                        =     ARRAY[0..0] OF FSSpec;    FSSpecArrayPtr                        =     ^FSSpecArray;    FSSpecArrayHandle                        =     ^FSSpecArrayPtr;File and Directory Parameter Blocks    ParamBlkType                        =      (ioParam, fileParam, volumeParam, cntrlParam,                                    slotDevParam, multiDevParam, accessParam,                                    objParam, copyParam, wdParam, fidParam, csParam,                                    foreignPrivsParam);    ParmBlkPtr                        =    ^ParamBlockRec;    ParamBlockRec                        =                        {basic File Manager parameter block}    RECORD                qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {queue type}        ioTrap:                        Integer;                    {routine trap}        ioCmdAddr:                        Ptr;                    {routine address}        ioCompletion:                        ProcPtr;                    {completion routine}        ioResult:                        OSErr;                    {result code}        ioNamePtr:                        StringPtr;                    {pointer to pathname}        ioVRefNum:                        Integer;                    {volume specification}    CASE ParamBlkType OF    ioParam:                          (ioRefNum:                            Integer;                    {file reference number}        ioVersNum:                        SignedByte;                    {version number}        ioPermssn:                        SignedByte;                    {read/write permission}        ioMisc:                        Ptr;                    {miscellaneous}        ioBuffer:                        Ptr;                    {data buffer}        ioReqCount:                        LongInt;                    {requested number of bytes}        ioActCount:                        LongInt;                    {actual number of bytes}        ioPosMode:                        Integer;                    {positioning mode and newline char.}        ioPosOffset:                        LongInt);                    {positioning offset}    fileParam:                          (ioFRefNum:                            Integer;                    {file reference number}        ioFVersNum:                        SignedByte;                    {file version number (unused)}        filler1:                        SignedByte;                    {reserved}        ioFDirIndex:                        Integer;                    {directory index}        ioFlAttrib:                        SignedByte;                    {file attributes}        ioFlVersNum:                        SignedByte;                    {file version number (unused)}        ioFlFndrInfo:                        FInfo;                    {information used by the Finder}        ioFlNum:                        LongInt;                    {file ID}        ioFlStBlk:                        Integer;                    {first alloc. blk. of data fork}        ioFlLgLen:                        LongInt;                    {logical EOF of data fork}        ioFlPyLen:                        LongInt;                    {physical EOF of data fork}        ioFlRStBlk:                        Integer;                    {first alloc. blk. of resource fork}        ioFlRLgLen:                        LongInt;                    {logical EOF of resource fork}        ioFlRPyLen:                        LongInt;                    {physical EOF of resource fork}        ioFlCrDat:                        LongInt;                    {date and time of creation}        ioFlMdDat:                        LongInt);                    {date and time of last modification}    volumeParam:                          (filler2:                            LongInt;                    {reserved}        ioVolIndex:                        Integer;                    {volume index}        ioVCrDate:                        LongInt;                    {date and time of initialization}        ioVLsBkUp:                        LongInt;                    {date and time of last modification}        ioVAtrb:                        Integer;                    {volume attributes}        ioVNmFls                        Integer;                    {number of files in root directory}        ioVDirSt:                        Integer;                    {first block of directory}        ioVBlLn:                        Integer;                    {length of directory in blocks}        ioVNmAlBlks:                        Integer;                    {number of allocation blocks}        ioVAlBlkSiz:                        LongInt;                    {size of allocation blocks}        ioVClpSiz:                        LongInt;                    {number of bytes to allocate}        ioAlBlSt:                        Integer;                    {first block in block map}        ioVNxtFNum:                        LongInt;                    {next unused file ID}        ioVFrBlk:                        Integer);                    {number of unused allocation blocks}    END;    HParmBlkPtr                         =     ^HParamBlockRec;    HParamBlockRec                        =                         {HFS parameter block}    RECORD            qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {queue type}        ioTrap:                        Integer;                    {routine trap}        ioCmdAddr:                        Ptr;                    {routine address}        ioCompletion:                        ProcPtr;                    {completion routine}        ioResult:                        OSErr;                    {result code}        ioNamePtr:                        StringPtr;                    {pointer to pathname}        ioVRefNum:                        Integer;                    {volume specification}    CASE ParamBlkType OF    ioParam:      (ioRefNum:                            Integer;                    {file reference number}        ioVersNum:                        SignedByte;                    {version number}        ioPermssn:                        SignedByte;                    {read/write permission}        ioMisc:                        Ptr;                    {miscellaneous}        ioBuffer:                        Ptr;                    {data buffer}        ioReqCount:                        LongInt;                    {requested number of bytes}        ioActCount:                        LongInt;                    {actual number of bytes}        ioPosMode:                        Integer;                    {positioning mode and newline char.}        ioPosOffset:                        LongInt);                    {positioning offset}    fileParam:                              (ioFRefNum:                            Integer;                    {file reference number}        ioFVersNum:                        SignedByte;                    {file version number (unused)}        filler1:                        SignedByte;                    {reserved}        ioFDirIndex:                        Integer;                    {directory index}        ioFlAttrib:                        SignedByte;                    {file attributes}        ioFlVersNum:                        SignedByte;                    {file version number (unused)}        ioFlFndrInfo:                        FInfo;                    {information used by the Finder}        ioDirID:                        LongInt;                    {directory ID or file ID}        ioFlStBlk:                        Integer;                    {first alloc. blk. of data fork}        ioFlLgLen:                        LongInt;                    {logical EOF of data fork}        ioFlPyLen:                        LongInt;                    {physical EOF of data fork}        ioFlRStBlk:                        Integer;                    {first alloc. blk. of resource fork}        ioFlRLgLen:                        LongInt;                    {logical EOF of resource fork}        ioFlRPyLen:                        LongInt;                    {physical EOF of resource fork}        ioFlCrDat:                        LongInt;                    {date and time of creation}        ioFlMdDat:                        LongInt);                    {date and time of last modification}    volumeParam:                              (filler2:                            LongInt;                    {reserved}        ioVolIndex:                        Integer;                    {volume index}        ioVCrDate:                        LongInt;                    {date and time of initialization}        ioVLsMod:                        LongInt;                    {date and time of last modification}        ioVAtrb:                        Integer;                    {volume attributes}        ioVNmFls:                        Integer;                    {number of files in root directory}        ioVBitMap:                        Integer;                    {first block of volume bitmap}        ioAllocPtr:                        Integer;                    {first block of next new file}        ioVNmAlBlks:                        Integer;                    {number of allocation blocks}        ioVAlBlkSiz:                        LongInt;                    {size of allocation blocks}        ioVClpSiz:                        LongInt;                    {default clump size}        ioAlBlSt:                        Integer;                    {first block in volume map}        ioVNxtCNID:                        LongInt;                    {next unused node ID}        ioVFrBlk:                        Integer;                    {number of unused allocation blocks}        ioVSigWord:                        Integer;                    {volume signature}        ioVDrvInfo:                        Integer;                    {drive number}        ioVDRefNum:                        Integer;                    {driver reference number}        ioVFSID:                        Integer;                    {file-system identifier}        ioVBkUp:                        LongInt;                    {date and time of last backup}        ioVSeqNum:                        Integer;                    {used internally}        ioVWrCnt                        LongInt;                    {volume write count}        ioVFilCnt:                        LongInt;                    {number of files on volume}        ioVDirCnt:                        LongInt;                    {number of directories on volume}        ioVFndrInfo:                        ARRAY[1..8] OF LongInt);                                                    {information used by the Finder}    accessParam:      (filler3:                            Integer;                    {reserved}        ioDenyModes:                        Integer;                    {access mode information}        filler4:                        Integer;                    {reserved}        filler5:                        SignedByte;                    {reserved}        ioACUser:                        SignedByte;                    {user access rights}        filler6:                        LongInt;                    {reserved}        ioACOwnerID:                        LongInt;                    {owner ID}        ioACGroupID:                        LongInt;                    {group ID}        ioACAccess:                        LongInt);                    {directory access rights}    objParam:                              (filler7:                            Integer;                    {reserved}        ioObjType:                        Integer;                    {function code}        ioObjNamePtr:                        Ptr;                    {ptr to returned creator/group name}        ioObjID:                        LongInt);                    {creator/group ID}    copyParam:                              (ioDstVRefNum:                            Integer;                    {destination volume identifier}        filler8:                        Integer;                    {reserved}        ioNewName:                        Ptr;                    {pointer to destination pathname}        ioCopyName:                        Ptr;                    {pointer to optional name}        ioNewDirID:                        LongInt);                    {destination directory ID}    wdParam:                              (filler9:                            Integer;                    {reserved}        ioWDIndex:                        Integer;                    {working directory index}        ioWDProcID:                        LongInt;                    {working directory user identifier}        ioWDVRefNum:                        Integer;                    {working directory’s vol. ref. num.}        filler10:                        Integer;                    {reserved}        filler11:                        LongInt;                    {reserved}        filler12:                        LongInt;                    {reserved}        filler13:                        LongInt;                    {reserved}        ioWDDirID:                        LongInt);                    {working directory’s directory ID}    fidParam:                          (filler14:                            LongInt;                    {reserved}        ioDestNamePtr:                        StringPtr;                    {pointer to destination filename}        filler15:                        LongInt;                    {reserved}        ioDestDirID:                        LongInt;                    {destination parent directory ID}        filler16:                        LongInt;                    {reserved}        filler17:                        LongInt;                    {reserved}        ioSrcDirID:                        LongInt;                    {source parent directory ID}        filler18:                        Integer;                    {reserved}        ioFileID:                        LongInt);                    {file ID}    csParam:          (ioMatchPtr:                            FSSpecArrayPtr;                    {pointer to array of matches}        ioReqMatchCount:                        LongInt;                    {max. number of matches to return}        ioActMatchCount:                        LongInt;                    {actual number of matches}        ioSearchBits:                        LongInt;                    {enable bits for matching rules}        ioSearchInfo1:                        CInfoPBPtr;                    {pointer to values and lower bounds}        ioSearchInfo2:                        CInfoPBPtr;                    {pointer to masks and upper bounds}        ioSearchTime:                        LongInt;                    {maximum time to search}        ioCatPosition:                        CatPositionRec;                    {current catalog position}        ioOptBuffer:                        Ptr;                    {pointer to optional read buffer}        ioOptBufSize:                        LongInt);                    {length of optional read buffer}    foreignPrivParam:      (filler21:                                    LongInt;                {reserved}        filler22:                                LongInt;                {reserved}        ioForeignPrivBuffer:                                Ptr;                {privileges data buffer}        ioForeignPrivReqCount:                                LongInt;                {size of buffer}        ioForeignPrivActCount:                                LongInt;                {amount of buffer used}        filler23:                                LongInt;                {reserved}        ioForeignPrivDirID:                                LongInt;                {parent directory ID of }                                                        { foreign file or directory}        ioForeignPrivInfo1:                                LongInt;                {privileges data}        ioForeignPrivInfo2            :                    LongInt;                {privileges data}        ioForeignPrivInfo3:                                LongInt;                {privileges data}        ioForeignPrivInfo4:                                LongInt);                {privileges data}    END;Catalog Information Parameter Blocks    CInfoType                        =    (hfileInfo, dirInfo);                CInfoPBPtr                         = ^CInfoPBRec;    CInfoPBRec                        =    {catalog information parameter block}    RECORD        qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {queue type}        ioTrap:                        Integer;                    {routine trap}        ioCmdAddr:                        Ptr;                    {routine address}        ioCompletion:                        ProcPtr;                    {completion routine}        ioResult:                        OSErr;                    {result code}        ioNamePtr:                        StringPtr;                    {pointer to pathname}        ioVRefNum:                        Integer;                    {volume specification}        ioFRefNum:                        Integer;                    {file reference number}        ioFVersNum:                        SignedByte;                    {version number}        filler1:                        SignedByte;                    {reserved}        ioFDirIndex:                        Integer;                    {directory index}        ioFlAttrib:                        SignedByte;                    {file attributes}        ioACUser:                        SignedByte;                    {directory access rights}    CASE CInfoType OF    hFileInfo:                          (ioFlFndrInfo:                            FInfo;                    {information used by the Finder}        ioDirID:                        LongInt;                    {directory ID or file ID}        ioFlStBlk:                        Integer;                    {first alloc. blk. of data fork}        ioFlLgLen:                        LongInt;                    {logical EOF of data fork}        ioFlPyLen:                        LongInt;                    {physical EOF of data fork}        ioFlRStBlk:                        Integer;                    {first alloc. blk. of resource fork}        ioFlRLgLen:                        LongInt;                    {logical EOF of resource fork}        ioFlRPyLen:                        LongInt;                    {physical EOF of resource fork}        ioFlCrDat:                        LongInt;                    {date and time of creation}        ioFlMdDat:                        LongInt;                    {date and time of last modification}        ioFlBkDat:                        LongInt;                    {date and time of last backup}        ioFlXFndrInfo:                        FXInfo;                    {additional Finder information}        ioFlParID:                        LongInt;                    {file parent directory ID (integer)}        ioFlClpSiz:                        LongInt)    ;                {file's clump size}    dirInfo:                          (ioDrUsrWds:                            DInfo;                    {information used by the Finder}        ioDrDirID:                        LongInt;                    {directory ID}        ioDrNmFls:                        Integer;                    {number of files in directory}        filler3:                        ARRAY[1..9] OF Integer;        ioDrCrDat:                        LongInt;                    {date and time of creation}        ioDrMdDat:                        LongInt;                    {date and time of last modification}        ioDrBkDat:                        LongInt;                    {date and time of last backup}        ioDrFndrInfo:                        DXInfo;                    {additional Finder information}        ioDrParID:                        LongInt);                    {directory's parent directory ID}    END;Catalog Position Record    CatPositionRec                        =                {catalog position record}    RECORD                initialize:                        LongInt;                                        {starting point}        priv:                        ARRAY[1..6] OF Integer;                                        {private data}    END;Catalog Move Parameter Block    CMovePBPtr                        = ^CMovePBRec;    CMovePBRec                        =                         {catalog move parameter block}    RECORD        qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {queue type}        ioTrap:                        Integer;                    {routine trap}        ioCmdAddr:                        Ptr;                    {routine address}        ioCompletion:                        ProcPtr;                    {completion routine}        ioResult:                        OSErr;                    {result code}        ioNamePtr:                        StringPtr;                    {pointer to pathname}        ioVRefNum:                        Integer;                    {volume specification}        filler1:                        LongInt;                    {reserved}        ioNewName:                        StringPtr;                    {name of new directory}        filler2:                        LongInt;                    {reserved}        ioNewDirID:                        LongInt;                    {directory ID of new directory}        filler3:                        ARRAY[1..2] OF LongInt;                                {reserved}        ioDirID:                        LongInt;                    {directory ID of current directory}    END;Working Directory Parameter Block    WDPBPtr                        = ^WDPBRec;    WDPBRec                        =                        {working directory parameter block}    RECORD                qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {queue type}        ioTrap:                        Integer;                    {routine trap}        ioCmdAddr:                        Ptr;                    {routine address}        ioCompletion:                        ProcPtr;                    {completion routine}        ioResult:                        OSErr;                    {result code}        ioNamePtr:                        StringPtr;                    {pointer to pathname}        ioVRefNum:                        Integer;                    {volume specification}        filler1:                        Integer;                    {reserved}        ioWDIndex:                        Integer;                    {working directory index}        ioWDProcID:                        LongInt;                    {working directory user identifier}        ioWDVRefNum:                        Integer;                    {working directory’s vol. ref. num.}        filler2:                        ARRAY[1..7] OF Integer;                                {reserved}        ioWDDirID:                        LongInt;                    {working directory's directory ID}    END;File Control Block Parameter Block    FCBPBPtr                        = ^FCBPBRec;    FCBPBRec                        =                        {file control block parameter block}    RECORD                qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {queue type}        ioTrap:                        Integer;                    {routine trap}        ioCmdAddr:                        Ptr;                    {routine address}        ioCompletion:                        ProcPtr;                    {completion routine}        ioResult:                        OSErr;                    {result code}        ioNamePtr:                        StringPtr;                    {pointer to pathname}        ioVRefNum:                        Integer;                    {volume specification}        ioRefNum:                        Integer;                    {file reference number}        filler:                        Integer;                    {reserved}        ioFCBIndx:                        Integer;                    {FCB index}        filler1                        Integer;                    {reserved}        ioFCBFlNm:                        LongInt;                    {file ID}        ioFCBFlags:                        Integer;                    {flags}        ioFCBStBlk:                        Integer;                    {first allocation block of file}        ioFCBEOF:                        LongInt;                    {logical end-of-file}        ioFCBPLen:                        LongInt;                    {physical end-of-file}        ioFCBCrPs:                        LongInt;                    {position of the file mark}        ioFCBVRefNum:                        Integer;                    {volume reference number}        ioFCBClpSiz:                        LongInt;                    {file's clump size}        ioFCBParID:                        LongInt;                    {parent directory ID}    END;Volume Attributes Buffer    GetVolParmsInfoBuffer =    RECORD        vMVersion:                        Integer;                    {version number}        vMAttrib:                        LongInt;                    {volume attributes}        vMLocalHand:                        Handle;                    {reserved}        vMServerAdr:                        LongInt;                    {network server address}        vMVolumeGrade:                        LongInt;                    {relative speed rating}        vMForeignPrivID:                        Integer;                    {foreign privilege model}    END;Volume Mounting Information Records    VolumeType                            =    OSType;    VolMountInfoPtr                            =    ^VolMountInfoHeader;    VolMountInfoHeader                            =                    {volume mounting information}    RECORD        length:                        Integer;                    {length of mounting information}        media:                        VolumeType;                    {type of volume}    END;    AFPVolMountInfoPtr                             =    ^AFPVolMountInfo;    AFPVolMountInfo                            =                     {AFP volume mounting information}    RECORD        length:                        Integer;                    {length of mounting information}        media:                        VolumeType;                    {type of volume}        flags:                        Integer;                    {reserved; must be set to 0}        nbpInterval:                        SignedByte;                    {NBP retry interval}        nbpCount:                        SignedByte;                    {NBP retry count}        uamType:                        Integer;                    {user authentication method}        zoneNameOffset:                        Integer;                    {offset to zone name}        serverNameOffset:                        Integer;                    {offset server name}            volNameOffset:                        Integer;                    {offset to volume name}        userNameOffset:                        Integer;                    {offset to user name}        userPasswordOffset:                                Integer;                    {offset to user password}        volPasswordOffset:                                Integer;                    {offset to volume password}        AFPData:                        PACKED ARRAY[1..144] OF CHAR;                                                    {standard AFP mounting info}    END;Internal Data TypesVolume and File Control Blocks    VCB                             =                {volume control block}    RECORD                qLink:                        QElemPtr;                {next queue entry}        qType:                        Integer;                {queue type}        vcbFlags:                        Integer;                {volume flags (bit 15 = 1 if dirty)}        vcbSigWord:                        Integer;                {volume signature}        vcbCrDate:                        LongInt;                {date and time of volume creation}        vcbLsMod:                        LongInt;                {date and time of last modification}        vcbAtrb:                        Integer;                {volume attributes}        vcbNmFls:                        Integer;                {number of files in root directory}        vcbVBMSt:                        Integer;                {first block of volume bitmap}        vcbAllocPtr:                        Integer;                {start of next allocation search}        vcbNmAlBlks:                        Integer;                {number of allocation blocks in volume}        vcbAlBlkSiz:                        LongInt;                {size (in bytes) of allocation blocks}        vcbClpSiz:                        LongInt;                {default clump size}        vcbAlBlSt:                        Integer;                {first allocation block in volume}        vcbNxtCNID:                        LongInt;                {next unused catalog node ID}        vcbFreeBks:                        Integer;                {number of unused allocation blocks}        vcbVN:                        String[27];                {volume name}        vcbDrvNum:                        Integer;                {drive number}        vcbDRefNum:                        Integer;                {driver reference number}        vcbFSID:                        Integer;                {file-system identifier}        vcbVRefNum:                        Integer;                {volume reference number}        vcbMAdr:                        Ptr;                {used internally}        vcbBufAdr:                        Ptr;                {used internally}        vcbMLen:                        Integer;                {used internally}        vcbDirIndex:                        Integer;                {used internally}        vcbDirBlk:                        Integer;                {used internally}        vcbVolBkUp:                        LongInt;                {date and time of last backup}        vcbVSeqNum:                        Integer;                {volume backup sequence number}        vcbWrCnt:                        LongInt;                {volume write count}        vcbXTClpSiz:                        LongInt;                {clump size for extents overflow file}        vcbCTClpSiz:                        LongInt;                {clump size for catalog file}        vcbNmRtDirs:                        Integer;                {number of directories in root dir.}        vcbFilCnt:                        LongInt;                {number of files in volume}        vcbDirCnt:                        LongInt;                {number of directories in volume}        vcbFndrInfo:                        ARRAY[1..8] OF LongInt;                                                {information used by the Finder}        vcbVCSize:                        Integer;                {used internally}        vcbVBMCSiz:                        Integer;                {used internally}        vcbCtlCSiz:                        Integer;                {used internally}        vcbXTAlBlks:                        Integer;                {size of extents overflow file}        vcbCTAlBlks:                        Integer;                {size of catalog file}        vcbXTRef:                        Integer;                {ref. num. for extents overflow file}        vcbCTRef:                        Integer;                {ref. num. for catalog file}        vcbCtlBuf:                        Ptr;                {ptr. to extents and catalog caches}        vcbDirIDM:                        LongInt;                {directory last searched}        vcbOffsM:                        Integer;                {offspring index at last search}    END;    FCB                            =                {file control block}    RECORD        fcbFlNum:                        LongInt;                {file ID}        fcbFlags:                        Integer;                {file flags}        fcbSBlk:                        Integer;                {first allocation block of file}        fcbEOF:                        LongInt;                {logical end-of-file}        fcbPLen:                        LongInt;                {physical end-of-file}        fcbCrPs:                        LongInt;                {current file mark position}        fcbVPtr:                        Ptr;                {pointer to volume control block}        fcbBfAdr:                        Ptr;                {pointer to access path buffer}        fcbFlPos:                        Integer;                {unused}        fcbClmpSize:                        LongInt;                {file clump size}        fcbBTCBPtr:                        Ptr;                {pointer to B*-tree control block}        fcbExtRec;                        ExtDataRec;                {first three file extents}        fcbFType:                        LongInt;                {file’s four Finder type bytes}        fcbCatPos:                        LongInt;                {catalog hint for use on Close}        fcbDirID:                        LongInt;                {file’s parent directory ID}        fcbCName:                        String[31];                {name of file}    END;Drive Queue Elements    DrvQEl                            =                    {drive queue element}    RECORD                qLink:                        QElemPtr;                    {next queue entry}        qType:                        Integer;                    {flag for dQDrvSz and dQDrvSz2}        dQDrive:                        Integer;                    {drive number}        dQRefNum:                        Integer;                    {driver reference number}        dQFSID:                        Integer;                    {file-system identifier}        dQDrvSz:                        Integer;                    {number of logical blocks on drive}        dQDrvSz2:                        Integer;                    {additional field for large drives}    END;High-Level File Access RoutinesReading, Writing, and Closing FilesFUNCTION FSRead    (refNum: Integer; VAR count: LongInt; buffPtr: Ptr): OSErr;FUNCTION FSWrite    (refNum: Integer; VAR count: LongInt; buffPtr: Ptr): OSErr;FUNCTION FSClose    (refNum: Integer): OSErr;Manipulating the File MarkFUNCTION GetFPos    (refNum: Integer; VAR filePos: LongInt): OSErr;FUNCTION SetFPos    (refNum: Integer; posMode: Integer; posOff: LongInt): OSErr;Manipulating the End-of-FileFUNCTION GetEOF    (refNum: Integer; VAR logEOF: LongInt): OSErr;FUNCTION SetEOF    (refNum: Integer; logEOF: LongInt): OSErr;Allocating File BlocksFUNCTION Allocate    (refNum: Integer; VAR count: LongInt): OSErr;FUNCTION AllocContig    (refNum: Integer; VAR count: LongInt): OSErr;Low-Level File Access RoutinesReading, Writing, and Closing FilesFUNCTION PBRead    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBReadSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBReadAsync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBWrite    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBWriteSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBWriteAsync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBClose    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBCloseSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBCloseAsync    (paramBlock: ParmBlkPtr): OSErr;Manipulating the File MarkFUNCTION PBGetFPos    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBGetFPosSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBGetFPosAsync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBSetFPos    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBSetFPosSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBSetFPosAsync    (paramBlock: ParmBlkPtr): OSErr;Manipulating the End-of-FileFUNCTION PBGetEOF    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBGetEOFSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBGetEOFAsync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBSetEOF    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBSetEOFSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBSetEOFAsync    (paramBlock: ParmBlkPtr): OSErr;Allocating File BlocksFUNCTION PBAllocate    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBAllocateSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBAllocateAsync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBAllocContig    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBAllocContigSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBAllocContigAsync    (paramBlock: ParmBlkPtr): OSErr;Updating FilesFUNCTION PBFlushFile    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBFlushFileSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBFlushFileAsync    (paramBlock: ParmBlkPtr): OSErr;High-Level Volume Access RoutinesUnmounting VolumesFUNCTION UnmountVol    (volName: StringPtr; vRefNum: Integer): OSErr;FUNCTION Eject    (volName: StringPtr; vRefNum: Integer): OSErr;Updating VolumesFUNCTION FlushVol    (volName: StringPtr; vRefNum: Integer): OSErr;Manipulating the Default VolumeFUNCTION GetVol    (volName: StringPtr; VAR vRefNum: Integer): OSErr;FUNCTION SetVol    (volName: StringPtr; vRefNum: Integer): OSErr;FUNCTION HGetVol    (volName: StringPtr; VAR vRefNum: Integer; VAR dirID: LongInt): OSErr;FUNCTION HSetVol    (volName: StringPtr; vRefNum: Integer; dirID: LongInt): OSErr;Obtaining Volume InformationFUNCTION GetVInfo    (drvNum: Integer; volName: StringPtr; VAR vRefNum: Integer; VAR freeBytes: LongInt): OSErr;FUNCTION GetVRefNum    (refNum: Integer; VAR vRefNum: Integer): OSErr;Low-Level Volume Access RoutinesMounting and Unmounting VolumesFUNCTION PBMountVol    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBUnmountVol    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBEject    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBOffLine    (paramBlock: ParmBlkPtr): OSErr;Updating VolumesFUNCTION PBFlushVol    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBFlushVolSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBFlushVolAsync    (paramBlock: ParmBlkPtr): OSErr;Obtaining Volume InformationFUNCTION PBGetVInfo    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBGetVInfoSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBGetVInfoAsync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBSetVInfo    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBSetVInfoSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBSetVInfoAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHGetVInfo    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHGetVInfoSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHGetVInfoAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHGetVolParms    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHGetVolParmsSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHGetVolParmsAsync    (paramBlock: HParmBlkPtr): OSErr;Manipulating the Default VolumeFUNCTION PBGetVol    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBGetVolSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBGetVolAsync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBSetVol    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBSetVolSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBSetVolAsync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBHGetVol    (paramBlock: WDPBPtr; async: Boolean): OSErr;FUNCTION PBHGetVolSync    (paramBlock: WDPBPtr): OSErr;FUNCTION PBHGetVolAsync    (paramBlock: WDPBPtr): OSErr;FUNCTION PBHSetVol    (paramBlock: WDPBPtr; async: Boolean): OSErr;FUNCTION PBHSetVolSync    (paramBlock: WDPBPtr): OSErr;FUNCTION PBHSetVolAsync    (paramBlock: WDPBPtr): OSErr;File System Specification RoutinesOpening FilesFUNCTION FSpOpenDF    (spec: FSSpec; permission: SignedByte; VAR refNum: Integer): OSErr;FUNCTION FSpOpenRF    (spec: FSSpec; permission: SignedByte; VAR refNum: Integer): OSErr;Creating and Deleting Files and DirectoriesFUNCTION FSpCreate    (spec: FSSpec; creator: OSType; fileType: OSType; scriptTag: ScriptCode): OSErr;FUNCTION FSpDirCreate    (spec: FSSpec; scriptTag: ScriptCode; VAR createdDirID: LongInt): OSErr;FUNCTION FSpDelete    (spec: FSSpec): OSErr;Accessing Information about Files and DirectoriesFUNCTION FSpGetFInfo    (spec: FSSpec; VAR fndrInfo: FInfo): OSErr;FUNCTION FSpSetFInfo    (spec: FSSpec; fndrInfo: FInfo): OSErr;FUNCTION FSpSetFLock    (spec: FSSpec): OSErr;FUNCTION FSpRstFLock    (spec: FSSpec): OSErr;FUNCTION FSpRename    (spec: FSSpec; newName: Str255): OSErr;Moving Files or DirectoriesFUNCTION FSpCatMove    (source: FSSpec; dest: FSSpec): OSErr;Exchanging the Data in Two FilesFUNCTION FSpExchangeFiles    (source: FSSpec; dest: FSSpec): OSErr;Creating File System SpecificationsFUNCTION FSMakeFSSpec    (vRefNum: Integer; dirID: LongInt;fileName: Str255; VAR spec: FSSpec): OSErr;FUNCTION PBMakeFSSpec    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBMakeFSSpecSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBMakeFSSpecAsync    (paramBlock: HParmBlkPtr): OSErr;High-Level HFS RoutinesOpening FilesFUNCTION HOpenDF    (vRefNum: Integer; dirID: LongInt; fileName: Str255; permission: SignedByte; VAR refNum: Integer): OSErr;FUNCTION HOpenRF    (vRefNum: Integer; dirID: LongInt; fileName: Str255; permission: SignedByte; VAR refNum Integer): OSErr;FUNCTION HOpen    (vRefNum: Integer; dirID: LongInt; fileName: Str255; permission: SignedByte; VAR refNum: Integer): OSErr;Creating and Deleting Files and DirectoriesFUNCTION HCreate    (vRefNum: Integer; dirID: LongInt; fileName: Str255; creator: OSType; fileType: OSType): OSErr;FUNCTION DirCreate    (vRefNum: Integer; parentDirID: LongInt; directoryName: Str255; VAR createdDirID: LongInt): OSErr;FUNCTION HDelete    (vRefNum: Integer; dirID: LongInt; fileName: Str255): OSErr;Accessing Information about Files and DirectoriesFUNCTION HGetFInfo    (vRefNum: Integer; dirID: LongInt; fileName: Str255; VAR fndrInfo: FInfo): OSErr;FUNCTION HSetFInfo    (vRefNum: Integer; dirID: LongInt; fileName: Str255; fndrInfo: FInfo): OSErr;FUNCTION HSetFLock    (vRefNum: Integer; dirID: LongInt; fileName: Str255): OSErr;FUNCTION HRstFLock    (vRefNum: Integer; dirID: LongInt; fileName: Str255): OSErr;FUNCTION HRename    (vRefNum: Integer; dirID: LongInt; oldName: Str255; newName: Str255): OSErr;Moving Files or DirectoriesFUNCTION CatMove    (vRefNum: Integer; dirID: LongInt; oldName: Str255; newDirID: LongInt; newName: Str255): OSErr;Maintaining Working DirectoriesFUNCTION OpenWD    (vRefNum: Integer; dirID: LongInt; procID: LongInt; VAR wdRefNum: Integer): OSErr;FUNCTION CloseWD    (wdRefNum: Integer): OSErr;FUNCTION GetWDInfo    (wdRefNum: Integer; VAR vRefNum: Integer; VAR dirID: LongInt; VAR procID: LongInt): OSErr;Low-Level HFS RoutinesOpening FilesFUNCTION PBHOpenDF    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHOpenDFSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHOpenDFAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHOpenRF    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHOpenRFSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHOpenRFAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHOpen    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHOpenSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHOpenAsync    (paramBlock: HParmBlkPtr): OSErr;Creating and Deleting Files and DirectoriesFUNCTION PBHCreate    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHCreateSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHCreateAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBDirCreate    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBDirCreateSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBDirCreateAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHDelete    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHDeleteSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHDeleteAsync    (paramBlock: HParmBlkPtr): OSErr;Accessing Information about Files and DirectoriesFUNCTION PBGetCatInfo    (paramBlock: CInfoPBPtr; async: Boolean): OSErr;FUNCTION PBGetCatInfoSync    (paramBlock: CInfoPBPtr): OSErr;FUNCTION PBGetCatInfoAsync    (paramBlock: CInfoPBPtr): OSErr;FUNCTION PBSetCatInfo    (paramBlock: CInfoPBPtr; async: Boolean): OSErr;FUNCTION PBSetCatInfoSync    (paramBlock: CInfoPBPtr): OSErr;FUNCTION PBSetCatInfoAsync    (paramBlock: CInfoPBPtr): OSErr;FUNCTION PBHGetFInfo    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHGetFInfoSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHGetFInfoAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHSetFInfo    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHSetFInfoSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHSetFInfoAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHSetFLock    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHSetFLockSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHSetFLockAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHRstFLock    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHRstFLockSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHRstFLockAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHRename    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHRenameSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHRenameAsync    (paramBlock: HParmBlkPtr): OSErr;Moving Files or DirectoriesFUNCTION PBCatMove    (paramBlock: CMovePBPtr; async: Boolean): OSErr;FUNCTION PBCatMoveSync    (paramBlock: CMovePBPtr): OSErr;FUNCTION PBCatMoveAsync    (paramBlock: CMovePBPtr): OSErr;Maintaining Working DirectoriesFUNCTION PBOpenWD    (paramBlock: WDPBPtr; async: Boolean): OSErr;FUNCTION PBOpenWDSync    (paramBlock: WDPBPtr): OSErr;FUNCTION PBOpenWDAsync    (paramBlock: WDPBPtr): OSErr;FUNCTION PBCloseWD    (paramBlock: WDPBPtr; async: Boolean): OSErr;FUNCTION PBCloseWDSync    (paramBlock: WDPBPtr): OSErr;FUNCTION PBCloseWDAsync    (paramBlock: WDPBPtr): OSErr;FUNCTION PBGetWDInfo    (paramBlock: WDPBPtr; async: Boolean): OSErr;FUNCTION PBGetWDInfoSync    (paramBlock: WDPBPtr): OSErr;FUNCTION PBGetWDInfoAsync    (paramBlock: WDPBPtr): OSErr;Searching a CatalogFUNCTION PBCatSearch    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBCatSearchSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBCatSearchAsync    (paramBlock: HParmBlkPtr): OSErr;Exchanging the Data in Two FilesFUNCTION PBExchangeFiles    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBExchangeFilesSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBExchangeFilesAsync    (paramBlock: HParmBlkPtr): OSErr;Shared Environment RoutinesOpening Files While Denying AccessFUNCTION PBHOpenDeny    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHOpenDenySync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHOpenDenyAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHOpenRFDeny    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHOpenRFDenySync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHOpenRFDenyAsync    (paramBlock: HParmBlkPtr): OSErr;Locking and Unlocking File RangesFUNCTION PBLockRange    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBLockRangeSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBLockRangeAsync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBUnlockRange    (paramBlock: ParmBlkPtr; async: Boolean): OSErr;FUNCTION PBUnlockRangeSync    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBUnlockRangeAsync    (paramBlock: ParmBlkPtr): OSErr;Manipulating Share PointsFUNCTION PBShare    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBShareSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBShareAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBUnshare    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBUnshareSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBUnshareAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBGetUGEntry    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBGetUGEntrySync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBGetUGEntryAsync    (paramBlock: HParmBlkPtr): OSErr;Controlling Directory AccessFUNCTION PBHGetDirAccess    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHGetDirAccessSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHGetDirAccessAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHSetDirAccess    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHSetDirAccessSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHSetDirAccessAsync    (paramBlock: HParmBlkPtr): OSErr;Mounting VolumesFUNCTION PBGetVolMountInfoSize    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBGetVolMountInfo    (paramBlock: ParmBlkPtr): OSErr;FUNCTION PBVolumeMount    (paramBlock: ParmBlkPtr): OSErr;Controlling Login AccessFUNCTION PBHGetLogInInfo    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHGetLogInInfoSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHGetLogInInfoAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHMapID    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHMapIDSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHMapIDAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHMapName    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHMapNameSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHMapNameAsync    (paramBlock: HParmBlkPtr): OSErr;Copying and Moving FilesFUNCTION PBHCopyFile    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHCopyFileSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHCopyFileAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHMoveRename    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBHMoveRenameSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBHMoveRenameAsync    (paramBlock: HParmBlkPtr): OSErr;File ID RoutinesResolving File ID ReferencesFUNCTION PBResolveFileIDRef    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBResolveFileIDRefSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBResolveFileIDRefAsync    (paramBlock: HParmBlkPtr): OSErr;Creating and Deleting File ID ReferencesFUNCTION PBCreateFileIDRef    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBCreateFileIDRefSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBCreateFileIDRefAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBDeleteFileIDRef    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBDeleteFileIDRefSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBDeleteFileIDRefAsync    (paramBlock: HParmBlkPtr): OSErr;Foreign File System RoutinesAccessing Privilege Information in Foreign File SystemsFUNCTION PBGetForeignPrivs    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBGetForeignPrivsSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBGetForeignPrivsAsync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBSetForeignPrivs    (paramBlock: HParmBlkPtr; async: Boolean): OSErr;FUNCTION PBSetForeignPrivsSync    (paramBlock: HParmBlkPtr): OSErr;FUNCTION PBSetForeignPrivsAsync    (paramBlock: HParmBlkPtr): OSErr;Utility RoutinesObtaining Queue HeadersFUNCTION GetFSQHdr    : QHdrPtr;FUNCTION GetVCBQHdr    : QHdrPtr;FUNCTION GetDrvQHdr    : QHdrPtr;Adding a DrivePROCEDURE AddDrive    (drvrRefNum: Integer; drvNum: Integer; qEl: DrvQElPtr);Obtaining File Control Block InformationFUNCTION PBGetFCBInfo    (paramBlock: FCBPBPtr; async: Boolean): OSErr;FUNCTION PBGetFCBInfoSync    (paramBlock: FCBPBPtr): OSErr;FUNCTION PBGetFCBInfoAsync    (paramBlock: FCBPBPtr): OSErr;Global VariablesBootDrive    Working directory reference number for startup volume (word)DefVCBPtr    Pointer to default volume control blockDrvQHdr    Drive queue header (10 bytes)FSFCBLen    Size of a file control block (word)FSQHdr     File I/O queue header (10 bytes)ToExtFS    Pointer to external file systemVCBQHdr     Volume control block queue header (10 bytes)Result CodesnoErr    0    No errornotOpenErr    –28    AppleTalk is not opendirFulErr     –33    File directory fulldskFulErr     –34    All allocation blocks on the volume are fullnsvErr    –35    Volume not foundioErr    –36    I/O errorbdNamErr    –37    Bad filename or volume namefnOpnErr     –38    File not openeofErr    –39    Logical end-of-file reachedposErr     –40    Attempt to position mark before start of filetmfoErr    –42    Too many files openfnfErr    –43    File not foundwPrErr    –44    Hardware volume lockfLckdErr    –45    File lockedvLckdErr    –46    Software volume lockfBsyErr     –47    File is busy; one or more files are open; directory not         empty or working directory control block is opendupFNErr     –48    A file with the specified name already existsopWrErr    –49    File already open for writingparamErr    –50    Parameter errorrfNumErr     –51    Reference number specifies nonexistent access pathgfpErr     –52    Error during GetFPosvolOfflinErr    –53    Volume is off linepermErr     –54    Attempt to open locked file for writingvolOnLinErr    –55    Specified volume is already mounted and on linensDrvErr     –56    Specified drive number doesn’t match any number        in the drive queuenoMacDskErr     –57    Volume lacks Macintosh-format directoryextFSErr    –58    External file systemfsRnErr     –59    Problem during renamebadMDBErr     –60    Bad master directory blockwrPermErr    –61    Read/write permission doesn’t allow writingmemFullErr    –108    Insufficient memory availabledirNFErr    –120    Directory not foundtmwdoErr    –121    Too many working directories openbadMovErr    –122    Attempted to move into offspringwrgVolTypeErr    –123    Not an HFS volumevolGoneErr    –124    Server volume has been disconnectedfsDSIntErr    –127    Internal file system errorfidNotFoundErr    –1300    File ID not foundfidExists    –1301    File ID already existsnotAFileErr    –1302    Specified file is a directorydiffVolErr    –1303    Files are on different volumessameFileErr    –1306    Files are the samecatalogChangedErr    –1304    Catalog has changed and catalog position record may         be invalidafpAccessDenied    –5000    The operation has failed because the user does not have        the correct access to the file or folderafpBadUAM    –5002    User authentication method is unknownafpBadVersNum    –5003    Workstation is using an AFP version that the server         doesn’t recognizeafpDenyConflict    –5006    The operation has failed because the permission or deny        mode conflicts with the mode in which the fork has        already been openedafpNoMoreLocks    –5015    Byte range locking has failed because the server cannot         lock any additional rangesafpNoServer    –5016    Server is not respondingafpRangeNotLocked    –5020    User has attempted to unlock a range that was not locked         by that userafpRangeOverlap    –5021    User attempted to lock some or all of a range that is        already lockedafpUserNotAuth    –5023    User authentication failed (usually, password is not        correct)afpObjectTypeErr    –5025    Object was a file, not a directory; or, this        directory is not a share pointafpContainsSharedErr    –5033    The directory contains a share pointafpPwdExpired    –5042    Password has expired on serverafpInsideSharedErr    –5043    The directory is inside a shared directoryafpBadDirIDType    –5060    Not a fixed directory ID volumeafpCantMountMoreSrvrs    –5061    Maximum number of volumes have been mountedafpAlreadyMounted    –5062    Volume already mountedafpSameNodeErr    –5063    Attempt to log on to a server running on the same machineAssembly-Language InformationConstants;flags in trap wordsasyncTrpBit                        EQU            10            ;set for an asynchronous callFSSpec Data StructurevRefNum    word    volume reference numberparID    long    parent directory IDname    64 bytes    filename or directory nameCatalog Position Data Structureinitialize    long    starting place for next searchpriv    12 bytes    private dataVolume Mounting Information Data Structurelength    word    length of recordmedia    4 bytes    type of volumeAFP Mounting Information Data Structurelength    word    length of recordmedia    4 bytes    type of volumeflags    word    reserved; must be 0nbpInterval    byte    NBP retry intervalnbpCount    byte    NBP retry countuamType    word    user authentication methodzoneNameOffset    word    offset to zone nameserverNameOffset    word    offset to server namevolNameOffset    word    offset to volume nameuserNameOffset    word    offset to user nameuserPassWordOffset    word    offset to user passwordvolPassWordOffset    word    offset to volume passwordAFPData    144 bytes    mounting dataVolume Control Block Data Structure qLink    long    pointer to next queue entryqType    word    queue typevcbFlags    word    volume flagsvcbSigWord    word    volume signaturevcbCrDate    long    date and time of initializationvcbLsMod    long    date and time of last modificationvcbAtrb    word    volume attributesvcbNmFls    word    number of files in root directoryvcbVBMSt     word    first block of volume bitmapvcbAllocPtr    word    start of next allocation searchvcbNmAlBlks    word    number of allocation blocks in volumevcbAlBlkSiz    long    size (in bytes) of allocation blockvcbClpSiz    long    default clump sizevcbAlBlSt    word    first allocation block in volumevcbNxtCNID    long    next unused catalog node IDvcbFreeBks    word    number of unused allocation blocksvcbVN    28 bytes    volume name preceded by length bytevcbDrvNum    word    drive numbervcbDRefNum    word    driver reference numbervcbFSID    word    file-system identifiervcbVRefNum    word    volume reference numbervcbMAdr    long    pointer to block mapvcbBufAdr    long    pointer to volume buffervcbMLen    word    number of bytes in block mapvcbDirIndex    word    reservedvcbDirBlk    word    reservedvcbVolBkUp    long    date and time of last backupvcbVSeqNum    word    volume backup sequence numbervcbWrCnt    long    volume write countvcbXTClpSiz    long    clump size for extents overflow filevcbCTClpSiz    long    clump size for catalog filevcbNmRtDirs    word    number of directories in root directoryvcbFilCnt    long    number of files in volumevcbDirCnt    long    number of directories in volumevcbFndrInfo    32 bytes    information used by the FindervcbVCSize    word    reservedvcbVBMCSiz    word    reservedvcbCtlCSiz    word    reservedvcbXTAlBks    word    size in blocks of extents overflow filevcbCTAlBks    word    size in blocks of catalog filevcbXTRef    word    file reference number for extents overflow filevcbCTRef    word    file reference number for catalog filevcbCtlBuf    long    pointer to extents and catalog tree cachesvcbDirIDM    long    directory last searchedvcbOffsM    word    offspring index at last searchFile Control Block Data StructurefcbFlNum    long    file IDfcbFlags    word    file flagsfcbSBlk    word    first allocation block of filefcbEOF    long    logical end-of-filefcbPLen    long    physical end-of-filefcbCrPs    long    current file mark positionfcbVPtr    long    pointer to volume control blockfcbBfAdr    long    pointer to access path bufferfcbFlPos    word    unusedfcbClmpSize    long    file’s clump sizefcbBTCBPtr    long    pointer to B*-tree control blockfcbExtRec    12 bytes    first three file extentsfcbFType    long    file’s four Finder type bytesfcbCatPos    long    catalog hint for use on closefcbDirID    long    file’s parent directory IDfcbCName    32 bytes    name of open file, preceded by length byteDrive Queue Entry Data StructureqLink     long    pointer to next queue entryqType    word    flag for dQDrvSiz and dQDrvSz2 fieldsdQDrive    word    drive numberdQRefNum    word    driver reference numberdQFSID    word    file-system identifierdQDrvSz    word    number of logical blocks on drivedQDrvSz2    word    additional field for large drivesCatalog Search Parameter Block    24    ioMatchPtr    long    pointer to match array    28    ioReqMatchCount    long    maximum match count    32    ioActMatchCount    long    actual match count    36    ioSearchBits    long    search criteria selector    40    ioSearchInfo1    long    pointer to search values and lower bounds    44    ioSearchInfo2    long    pointer to search values and upper bounds    48    ioSearchTime    long    time limit on search    52    ioCatPosition    16 bytes    catalog position record    68    ioOptBuffer    long    pointer to optional read buffer    72    ioOptBufSize    long    length of optional read bufferFile ID Parameter Block    24    filler14    long    filler    28    ioDestNamePtr    long    pointer to destination filename    32    filler15    long    filler    36    ioDestDirID    long    destination parent directory ID    40    filler16    long    filler    44    filler17    long    filler    48    ioSrcDirID    long    parent directory ID    52    filler18    2 bytes    filler    54    ioFileID    long    file IDForeign Privileges Parameter Block    24    filler21    long    filler    28    filler22    long    filler    32    ioForeignPrivBuffer    long    pointer to privileges data buffer    36    ioForeignPrivReqCount    long    size allocated for buffer    40    ioForeignPrivActCount    long    amount of buffer used    44    filler23    long    filler    48    ioForeignPrivDirID    long    parent directory ID of target    52    ioForeignPrivInfo1    long    privileges data    56    ioForeignPrivInfo2    long    privileges data    60    ioForeignPrivInfo3    long    privileges data    64    ioForeignPrivInfo4    long    privileges dataTrap Macros Requiring Routine Selectors_HFSDispatchSelector    Routine$0001    PBOpenWD$0002    PBCloseWD$0005    PBCatMove$0006    PBDirCreate$0007    PBGetWDInfo$0008    PBGetFCBInfo$0009    PBGetCatInfo$000A    PBSetCatInfo$000B    PBSetVInfo$0010    PBLockRange$0011    PBUnlockRange$0014    PBCreateFileIDRef$0015    PBDeleteFileIDRef$0016    PBResolveFileIDRef$0017    PBExchangeFiles$0018    PBCatSearch$001A    PBHOpenDF$001B    PBMakeFSSpec$0030    PBHGetVolParms$0031    PBHGetLogInInfo$0032    PBHGetDirAccess$0033    PBHSetDirAccess$0034    PBHMapID$0035    PBHMapName$0036    PBHCopyFile$0037    PBHMoveRename$0038    PBHOpenDeny$0039    PBHOpenRFDeny$003F    PBGetVolMountInfoSize$0040    PBGetVolMountInfo$0041    PBVolumeMount$0042    PBShare$0043    PBUnshare$0044    PBGetUGEntry$0060    PBGetForeignPrivs$0061    PBSetForeignPrivs_HighLevelFSDispatchSelector    Routine$0001    FSMakeFSSpec$0002    FSpOpenDF$0003    FSpOpenRF$0004    FSpCreate$0005    FSpDirCreate$0006    FSpDelete$0007    FSpGetFInfo$0008    FSpSetFInfo$0009    FSpSetFLock$000A    FSpRstFLock$000B    FSpRename$000C    FSpCatMove$000D    FSpOpenResFile$000E    FSpCreateResFile$000F    FSpExchangeFilesIndexAaccess privileges in foreign file systems?? to 18, 215 to 217AFP (AppleTalk Filing Protocol)17Allocate function114AppleTalk Filing Protocol (AFP)17Ccatalogssearching33 to 39, 192 to 193Ddefault directory31default volume30directoriesdescribed for PBCatSearch33specifying in HFS25directorydefault31Ffile attributesdefined35specifying in PBCatSearch33file IDscreating213deleting214exchanging193functions for manipulating?? to 213resolving212tracking files with18 to ??File Managercreating FSSpec records83 to ??, 157 to 158exchanging contents of two files?? to 157functions modified to accept FSSpec records?? to 155manipulating foreign access-control information?? to 18, 215 to 217mounting remote volumes204 to 206, ?? to 206, ?? to 210, ?? to 211reading volume information140 to 143searching a catalog33 to 39, 192 to 193testing for features27 to ??file reference numberand FCB buffer77file system specification19file system specification (FSSpec) recordsopening documents with?? to 83file system specification records82filenames, specifying in PBCatSearch33filesaccess control in foreign file systems?? to 18, 215 to 217described for PBCatSearch33specifying in HFS24 to ??tracking with file IDs18 to ??Finder informationspecifying in PBCatSearch33foreign file systems, access privileges in?? to 18, 215 to 217FSMakeFSSpec function83 to ??, 157FSpCreate function149FSpDelete function153FSpGetFInfo function152FSpOpenDF function147HHSetVol functionpossible problems using31Mmenu commandsOpen (File menu)83Oopeningfiles147Ppathnames25PBCatSearch function33 to 39, 192PBCreateFileIDRef function213PBDeleteFileIDRef function214PBExchangeFiles function193PBGetForeignPrivs function215PBGetUGEntry function201PBGetVolMountInfo function204PBGetVolMountInfoSize function204PBHGetVolParms function?? to 143PBHGetVolParms function29PBResolveFileIDRef function212PBSetForeignPrivs function216PBShare function199PBUnshare function200PBVolumeMount function205privilege models17Sscriptsspecifying when creating a file149Vvolumedefault30volumesdetermining the amount of free space on41 to 42identified in FSSpec records83mounting programmatically?? to 206searching the catalog33 to 39specifying25Zzz fsSBFlCrDat35zzfsRtDirID constant21zzfsRtParID constant21zzfsSBDrBkDat36zzfsSBDrCrDat36zzfsSBDrFndrInfo36zzfsSBDrMdDat36zzfsSBDrNmFls36zzfsSBDrParID36zzfsSBDrUsrWds36zzfsSBFlAttrib35zzfsSBFlBkDat36zzfsSBFlFndrInfo35zzfsSBFlLgLen35zzfsSBFlMdDat35zzfsSBFlParID36zzfsSBFLPyLen35zzfsSBFlRLgLen35zzfsSBFlRPyLen35zzfsSBFlXFndrInfo36zzfsSBFullName35zzfsSBNegate35zzfsSBPartialName35zzgestaltFullExtFSDispatching constant28zzgestaltHasFSSpecCalls constant28zzioCatPosition field37zzioSearchBits field35 to 36zzioSearchInfo1 and ioSearchInfo2 fields33zzioSearchTime field37zzvMForeignPrivID field18The Standard File PackageAbout the Standard File Package3-3Standard User Interfaces3-4Opening Files3-4Saving Files3-6Keyboard Equivalents3-7Customized User Interfaces3-8Saving Files3-8Opening Files3-9User Interface Guidelines3-10Using the Standard File Package3-11Presenting the Standard User Interface3-13Customizing the User Interface3-14Customizing Dialog Boxes3-16Writing a File Filter Function3-18Writing a Dialog Hook Function3-19Writing a Modal-Dialog Filter Function3-27Writing an Activation Procedure3-29Setting the Current Directory3-30Using the Original Procedures3-31Reference to the Standard File Package3-32Data Structures3-32Enhanced Standard File Reply Record3-32Original Standard File Reply Record3-34Routines3-35Saving Files3-35Opening Files3-39Summary of the Standard File Package3-453The Standard File PackageThis chapter describes how your application can use the Standard File Package to manage the user interface for naming and identifying files. The Standard File Package displays the dialog boxes that let the user specify the names and locations of files to be saved or opened, and it reports the user’s choices to your application.The Standard File Package supports both standard and customized dialog boxes. The standard dialog boxes are sufficient for applications that do not require additional controls or other elements in the user interface. The chapter “Introduction to File Management” earlier in this volume provides a detailed description of how to use two of the enhanced Standard File Package routines introduced in system software version 7.0 to display the standard dialog boxes. You need to read this chapter only if your application needs to use features not described in that earlier chapter (such as customized dialog boxes or a special file filter function) or if you want your application to run in an environment where the new routines are not available and your development system does not provide glue code that allows you to call the enhanced routines in earlier system software versions.To use this chapter, you should be familiar with the Dialog Manager, the Control Manager, and the Finder. You need to know about the Dialog Manager if you want to provide a modal-dialog filter function that handles events received from the Event Manager before they are passed to the ModalDialog procedure (which the Standard File Package uses to manage both standard and customized dialog boxes). You need to know about the Control Manager if you want to customize the user interface by adding controls (such as radio buttons or pop-up menus). You need to know about the Finder if your application supports stationery documents. See the appropriate chapters in the Macintosh Toolbox volume for specific information about these system software components.This chapter provides an introduction to the Standard File Package and then discussesn    how you can display the standard file selection dialog boxesn    how the Standard File Package interprets user actions in those dialog boxesn    how to manage customized dialog boxesn    how to set the directory whose contents are listed in a dialog boxn    how to use the original Standard File Package routinesAbout the Standard File PackageMacintosh applications typically have a File menu from which the user can save and open documents, via the Save, Save As, and Open commands. When the user chooses Open to open an existing document, your application needs to determine which document to open. Similarly, when the user chooses Save As, or Save when the document is untitled, your application needs to ask the user for the name and location of the file in which the document is to be saved.The Standard File Package provides a number of routines that handle the user interface between the user and your application when the user saves or opens a document. It displays dialog boxes through which the user specifies the name and location of the document to be saved or opened. It also allows your application to customize the dialog boxes and, through callback routines, to handle user actions during the dialogs. The Standard File Package procedures return information about the user’s choices to your application through a reply record.The Standard File Package is available in all versions of system software. However, significant improvements were made to the package in system software version 7.0. The Standard File Package in version 7.0 introducesn    a pair of simplified procedures (StandardGetFile and StandardPutFile) that you call to display and handle the standard Open and Save dialog boxesn    a pair of customizable procedures (CustomGetFile and CustomPutFile) that you call when you need more control over the interactionn    a new reply record (StandardFileReply) that identifies files and folders with a file system specification record and that accommodates the new Finder features introduced in system software version 7.0n    a new layout for the standard dialog boxesThis section describes in detail the standard and the customized user interfaces provided by the enhanced Standard File Package in system software version 7.0 and later. If your application is to run in earlier system software versions as well, you should read the section “Using the Original Procedures” later in this chapter.If you use the enhanced routines introduced in system software version 7.0, you must also support the Open Documents event.<36pt\>\x12 <8bat\>sStandard User InterfacesIf your application has no special interface requirements, you can use the StandardGetFile and StandardPutFile procedures to display the standard dialog boxes for opening and saving documents.Opening FilesYou use the StandardGetFile procedure when you want to let the user select a file to be opened. Figure 3-11 illustrates a sample dialog box displayed by StandardGetFile.The default Open dialog boxThe directory whose contents are listed in the dialog box displayed by StandardGetFile is known as the current directory. (In Figure 3-11, the current directory is named “screen dumps”.) The user can change the current directory in several ways. To ascend the directory hierarchy from the current directory, the user can click in the directory pop-up menu and select a new directory from among those in the menu. To ascend one level of the directory hierarchy, the user can click on the volume icon. To ascend immediately to the top of the directory hierarchy, the user can click the Desktop button. To descend the directory hierarchy, the user can double-click any of the folder names in the list (or select a folder by clicking its name once and then clicking the Open button). Whenever the current directory changes, the list of folders and files is updated to reflect the contents of the new current directory.The volume on which the current directory is located is the current disk, whose name is displayed to the right of the directory pop-up menu. If the current disk is a removable volume, the Eject button is active. The user can click Eject to eject the current disk and insert another, which then becomes the current disk. If the user inserts an uninitialized or otherwise unreadable disk, the Standard File Package calls the Disk Initialization Package to provide the standard user interface for initializing and naming a disk. See the chapter “The Disk Initialization Package” in this volume for details.Note that the list of files and folders always contains all folders in the current directory, but it might not contain all files in the current directory. When you call StandardGetFile, you can supply a list of the file types that your application can open. StandardGetFile then displays only files of the specified types. You can also supply your own file filter function to help determine which files are displayed. (See “Writing a File Filter Function” later in this chapter for details.)When the user is opening a document, StandardGetFile interprets some keystrokes as selectors in the displayed list. If the user presses A, for example, StandardGetFile selects the first item in the list that starts with the letter a (or, if no items in the list start with the letter a, the item that starts with the letter closest to a). The Standard File Package sets a timer on keystrokes: keystrokes in rapid succession form a string; keystrokes spaced in time are processed separately. See “Keyboard Equivalents” for a complete list of keyboard equivalents recognized by StandardGetFile.Saving FilesYou use the StandardPutFile procedure when you want to let the user specify a name and location for a file to be saved. Figure 3-12 illustrates a sample dialog box displayed by StandardPutFile.The default Save dialog boxThe dialog box displayed by StandardPutFile is similar to that displayed by StandardGetFile, but includes three additional items. The Save dialog box includes a filename field in which the user can type the desired name of the file to be saved. This filename field is a TextEdit field that permits all the standard editing operations (cut, copy, paste, and so forth). Above the filename field is a line of text specified by your application.When the user is saving a document, StandardPutFile can direct keystrokes to either of two targets: the filename field or the displayed list. When the dialog box first appears, keystrokes are directed to the filename field. If the user presses the Tab key or clicks to select an item in the displayed list, subsequent keystrokes are interpreted as selectors in the displayed list. Each time the user presses the Tab key, keyboard input shifts between the two targets.The third additional item in the Save dialog is the New Folder button. When the user clicks the New Folder button, the Standard File Package presents a subsidiary dialog box like the one shown in Figure 3-13.The New Folder dialog boxIf the user asks to save a file with a name that already exists at the specified location, the Standard File Package displays a subsidiary dialog box to verify that the new file should replace the existing file, as illustrated in Figure 3-14.The name conflict dialog boxThe StandardGetFile and StandardPutFile procedures always display the new dialog boxes. The procedures available before version 7.0 (SFGetFile, SFPutFile, SFPGetFile, and SFPPutFile) also display the new dialog boxes when running in version 7.0, unless your application has customized the dialog box. For more details on how the version 7.0 Standard File Package handles earlier procedures, see “Using the Original Procedures” later in this chapter.Keyboard EquivalentsThe Standard File Package recognizes a long list of keyboard equivalents during dialogs.Keystrokes    ActionUp Arrow    Scroll up (backward) through displayed listDown Arrow    Scroll down (forward) through displayed listCommand–Up Arrow    Display contents of parent directoryCommand–Down Arrow    Display contents of selected directory or volumeCommand–Left Arrow    Display contents of previous volumeCommand–Right Arrow    Display contents of next volumeCommand–Shift–Up Arrow    Display contents of desktopCommand-Shift-1    Eject disk in drive 1Command-Shift-2    Eject disk in drive 2Tab    Move to next keyboard targetReturn or Enter    Invoke the default option for the dialog box    (Open or Save)Escape or Command-.    CancelCommand-O    Open the selected itemCommand-D    Display contents of desktopCommand-N    Create a new folderOption-Command-O    Select the target of the selected alias item insteador Option-[click Open]     of opening itWhen the user uses a keyboard equivalent to select a button in the dialog box, the button flashes.Customized User InterfacesIn some cases, the standard user interfaces provided by the StandardGetFile and StandardPutFile procedures might not be adequate for the needs of your application. To handle such cases, the Standard File Package provides several routines that you can use to present a customized user interface when opening or saving files. This section gives some simple examples of how you might want to customize the user interfaces and suggests some guidelines you should follow when doing so.You should alter the standard user interfaces only if necessary. Apple Computer, Inc., does not guarantee future compatibility for your application if you use a customized dialog box.<36pt\>\x12 <8bat\>uSaving FilesPerhaps the most common reason to customize one of the Standard File Package dialog boxes is to allow the user to save a document in one of several file formats supported by the application. For example, a word-processing application might let the user save a document in the application’s own format, in an interchange format, as a file of type 'TEXT', and so on.It is usually best to allow the user to select a file format from within the dialog box displayed in response to a Save or Save As menu command. To do this, you need to add items to the standard dialog box and process user actions in those new items.If your application supports only a few file formats, you could simply add the required number of radio buttons to the standard dialog box, as illustrated in Figure 3-15. The application presenting this dialog box supports only two file formats, its own propriety format (SurfDraw) and the format used for startup screens.Customizing the Save dialog with radio buttonsIf your application supports more than a couple of alternate file formats, you could add a pop-up menu, as shown in Figure 3-16.Customizing the Save dialog with a pop-up menuOpening FilesYour application might also allow the user to open a number of different types of files. In this case, there is less need to customize the Open dialog than the Save dialog because you can simply list all the kinds of files your application supports. To avoid clutter in the list of files and folders, however, you might wish to filter out all but one of those types. In this way, the user can dynamically select which type of file to view in the list.Once again, you might accomplish this by adding radio buttons or a pop-up menu to the Open dialog, depending on the number of different file types your application supports. Figure 3-17 illustrates a customized Open dialog box that contains a pop-up menu. Only files of the indicated type (and, of course, folders) appear in the list of items available to open.Customizing the Open dialog with a pop-up menuFor details on some techniques you can use to add items to the standard user interface and process user actions with those additional items, see “Customizing the User Interface” later in this chapter. Note in particular that Listing 3-13, Listing 3-18, and Listing 3-19 together provide a fairly complete implementation of the pop-up menu illustrated in Figure 3-17.Remember that the user might also open one of your application’s documents from the Finder (by double-clicking its icon, for example). As a result, you should avoid customizing the Open dialog box. <36pt\>\x12 <8bat\>uUser Interface GuidelinesIn general, you should customize the user interface only if necessary. If you do modify the standard dialog boxes presented by the Standard File Package, you should keep these user interface guidelines in mind:n    Customize a dialog box only by adding items to the standard dialog boxes. Avoid removing existing items from the standard boxes or altering the operation of existing items. In particular, you should avoid modifying the keyboard equivalents recognized by the Standard File Package.n    Add only those items that are necessary for your application to complete the requested action successfully. Avoid adding items that provide unnecessary information or items that provide no information at all (such as logos, icons, or other “window-dressing”).n    Whenever possible, use controls such as radio buttons or pop-up menus whose effects are visible within the dialog box itself. Avoid controls whose use calls subsidiary modal dialog boxes that must be dismissed before the user can continue.n    Use controls or other items that are already familiar to the user. Avoid using customized controls that are not also used elsewhere in your application.Your overriding concern should be to make the customized file identification dialog boxes in your application as similar to the standard dialog boxes as possible while providing the additional capabilities you need.Using the Standard File PackageYou use the Standard File Package to handle the user interface when the user must specify a file to be saved or opened. You typically call the Standard File Package after the user chooses Save, Save As, or Open from the File menu.When saving a document, you call one of the PutFile procedures; when opening a document, you call one of the GetFile procedures. The Standard File Package in version 7.0 introduces two pairs of enhanced procedures:n    StandardPutFile and StandardGetFile, for presenting the standard interfacen    CustomPutFile and CustomGetFile, for presenting a customized interfaceBefore calling the enhanced Standard File Package procedures, verify that they are available by calling the Gestalt function with the gestaltStandardFileAttr selector. If Gestalt sets the gestaltStandardFile58 bit in the reply, the four enhanced procedures are available. For a complete description of the Gestalt function, see the chapter “Compatibility Guidelines” of the Overview volume.If the enhanced procedures are not available, you need to use the original Standard File Package procedures that are available in all system software versions:n    SFPutFile and SFGetFile, for presenting the standard interfacen    SFPPutFile and SFPGetFile, for presenting a customized interfaceThis section focuses on the enhanced procedures introduced in system software version 7.0. If you need to use the original procedures, see “Using the Original Procedures” later in this chapter. You can adapt most of the techniques shown in this section for use with the original procedures. In general, however, the original procedures are slightly harder to use and somewhat less powerful than their enhanced counterparts.All the enhanced procedures return the results of the dialog boxes in a new reply record, StandardFileReply.TYPE StandardFileReply =    RECORD        sfGood:                    Boolean;                {TRUE if user did not cancel}        sfReplacing:                    Boolean;                {TRUE if replacing file with same name}        sfType:                    OSType;                {file type}        sfFile:                    FSSpec;                {selected file, folder, or volume}        sfScript:                    ScriptCode;                {script of file, folder, or volume name}        sfFlags:                    Integer;                {Finder flags}        sfIsFolder:                    Boolean;                {selected item is a folder}        sfIsVolume:                    Boolean;                {selected item is a volume}        sfReserved1:                    LongInt;                {reserved}        sfReserved2:                    Integer;                {reserved}    END;The reply record identifies selected files with a file system specification (FSSpec) record. You can pass the FSSpec record directly to the File Manager functions that recognize FSSpec records, such as FSpOpenDF or FSpCreate. The reply record also contains additional fields that support the Finder features introduced in system software version 7.0.The sfGood field reports whether the reply record is valid—that is, whether your application can use the information in the other fields. The field is set to TRUE after the user clicks Save or Open, FALSE after the user clicks Cancel.Your application needs to look primarily at the sfFile and sfReplacing fields when the sfGood field contains TRUE. The sfFile field contains a file system specification record that describes the selected file or folder. If the selected file is a stationery pad, the reply record describes the file itself, not a copy of the file.The sfReplacing field reports whether a file to be saved replaces an existing file of the same name. This field is valid only after a call to the StandardPutFile or CustomPutFile procedure. Your application can rely on the value of this field instead of checking for and handling name conflicts itself.See “Enhanced Standard File Reply Record” on page 3-32 for a complete description of the fields of the StandardFileReply record.<36pt\>\x12 <8bat\>uThe Standard File Package fills in the reply record and returns when the user completes one of its dialog boxes—either by selecting a file and clicking Save or Open, or by clicking Cancel. Your application checks the values in the reply record to see what action to take, if any. If the selected item is an alias for another item, the Standard File Package resolves the alias and places a file system specification record for the target in the sfFile field when the user completes the dialog. (See the chapter “The Finder Interface” of the Macintosh Toolbox volume for a description of aliases.)Presenting the Standard User InterfaceYou can use the standard dialog boxes provided by the Standard File Package to prompt the user for the name of a file to open or a filename and location to use when saving a document. Use StandardGetFile to present the standard interface when opening a file and StandardPutFile to present the standard interface when saving a file.Listing 3-11 illustrates how your application can use StandardGetFile to elicit a file specification after the user chooses Open from the File menu.Handling the Open menu commandFUNCTION DoOpenCmd: OSErr;VAR                myReply:                StandardFileReply;                            {Standard File reply record}                    myTypes:                SFTypeList;                            {types of files to display}                    myErr:                OSErr;BEGIN                myTypes[0] := 'TEXT';                                            {display text files only}                    StandardGetFile(NIL, 1, myTypes, myReply);                    IF myReply.sfGood THEN                        myErr := DoOpenFile(myReply.sfFile)                ELSE                    myErr := UserCanceledErr;                DoOpenCmd := myErr;    END;If the user dismisses the dialog box by clicking the Open button, the reply record field myReply.sfGood is set to TRUE; in that case, the function defined in Listing 3-11 calls the application-defined function DoOpenFile, passing it the file system specification record contained in the reply record. For a sample definition of the DoOpenFile function, see the chapter “Introduction to File Management” in this volume.The third parameter to StandardGetFile is a list of file types that are to appear in the list of files and folders; the second parameter is the number of items in that list of file types. The list of file types is of type SFTypeList.TYPE                    SFTypeList                =    ARRAY[0..3] of OSType;If you need to display more than four types of files, you can define a new data type that is large enough to hold all the types you need. For example, you can define the data type MyTypeList to hold ten file types:TYPE                    MyTypeList                =    ARRAY[0..9] of OSType;                    MyTListPtr                =    ^MyTypeList;Listing 3-12 shows how to call StandardGetFile using an expanded type list.Specifying more than four file typesFUNCTION DoOpenCmd: OSErr;VAR                myReply:                StandardFileReply;                            {Standard File reply record}                    myTypes:                MyTypeList;                            {types of files to display}                    myErr:                OSErr;BEGIN                myTypes[0] := 'TEXT';                                            {first file type to display}                    {put other assignments here}                myTypes[9] := 'RTFT';                                            {tenth file type to display}                StandardGetFile(NIL, 1, MyTListPtr(myTypes)^, myReply);                    IF myReply.sfGood THEN                        myErr := DoOpenFile(myReply.sfFile)                ELSE                    myErr := UserCanceledErr;                DoOpenCmd := myErr;    END;To display all file types in the dialog box, pass –1 as the second parameter. Invisible files and folders are not shown in the dialog box unless you pass –1 in that parameter. If you pass –1 as the second parameter when calling CustomGetFile, the dialog box also lists folders; this is not true when calling StandardGetFile.<36pt\>\x12 <8bat\>uThe first parameter passed to StandardGetFile is the address of a file-filter function, a function that helps determine which files appear in the list of files to open. (In Listing 3-11, this address is NIL, indicating that all files of the specified type are to be listed.) See “Writing a File Filter Function” for details on defining a filter function for use with StandardGetFile.Customizing the User InterfaceIf your application requires it, you can customize the user interface for identifying files. To customize a dialog box, you shouldn    design your dialog box and create the resources that describe itn    write callback routines, if necessary, to process user actions in the dialog boxn    call the Standard File Package using the CustomPutFile and CustomGetFile procedures, passing the resource IDs of the customized dialog boxes and pointers to the callback routinesDepending on the level of customizing you require in your dialog box, you may need to write as many as four different callback routines:n    a file filter function for determining which files the user can openn    a dialog hook function for handling user actions in the dialog boxesn    a modal-dialog filter function for handling user events received from the Event Managern    an activation procedure for highlighting the display when keyboard input is directed at a customized field defined by your applicationTo provide the interface illustrated in Figure 3-17, for example, you could replace the definition of DoOpenCmd given earlier in Listing 3-11 by the definition given in Listing 3-13. Presenting a customized Open dialog boxFUNCTION DoOpenCmd: OSErr;VAR                myReply:                StandardFileReply;                            {Standard File reply record}                    myTypes:                SFTypeList;                            {types of files to display}                    myPoint:                Point;                            {upper-left corner of box}                myErr:                OSErr;CONST                kCustomGetDialog = 4000;                                            {resource ID of custom dialog}BEGIN                myErr := noErr;                SetPt(myPoint, -1, -1);                                            {center the dialog}                myTypes[0] := 'SRFD';                                            {SurfDraw files}                    myTypes[1] := 'STUP';                                            {startup screens}                    myTypes[2] := 'PICT';                                            {picture files}                    myTypes[3] := 'RTFT';                                            {rich text format}                    CustomGetFile(@MyCustomFileFilter, 4, myTypes, myReply,                                     kCustomGetDialog, myPoint, @MyDlgHook,                                     NIL, NIL, NIL, NIL);                    IF myReply.sfGood THEN                        myErr := DoOpenFile(myReply.sfFile);                DoOpenCmd := myErr;    END;In addition to the information passed to StandardGetFile, CustomGetFile requires the resource ID of the customized dialog box, the location of the dialog box on the screen, and pointers to any callback routines and private data you are using. In Listing 3-13, CustomGetFile is passed two callback routines, a file filter function (MyCustomFileFilter) and a dialog hook function (MyDlgHook). See Listing 3-18 and Listing 3-19 for sample definitions of these functions.You can also supply data of your own to be passed into the callback routines through a new parameter, yourDataPtr, that you can pass to CustomGetFile and CustomPutFile.Customizing Dialog BoxesTo describe a dialog box, you supply a 'DLOG' resource that defines the box itself and a 'DITL' resource that defines the items in the dialog box.Listing 3-14 shows the resource definition of the default Open dialog box, in Rez input format. (Rez is the resource compiler provided with Apple’s Macintosh Programmer’s Workshop [MPW]. For a description of Rez format, see the manual that accompanies the MPW software, MPW: Macintosh Programmer’s Development Environment.)The definition of the default Open dialog boxresource 'DLOG' (-6042, purgeable)                {                    {0, 0, 166, 344}, dBoxProc, invisible, noGoAway, 0,                     –6042, "", noAutoCenter                };Listing 3-15 shows the resource definition of the default Save dialog box, in Rez input format.The definition of the default Save dialog boxresource 'DLOG' (-6043, purgeable)                {                    {0, 0, 188, 344}, dBoxProc, invisible, noGoAway, 0,                     –6043, "", noAutoCenter                };You can also use the standalone resource editor ResEdit available from Apple Computer, Inc., or other resource-editing utilities available from third-part developers to create customized dialog box and dialog item list resources.<36pt\>\x12 <8bat\>uYou must provide an item list (in a 'DITL' resource with the ID specified in the 'DLOG' resource) for each dialog box you define. Add new items to the end of the default lists. CustomGetFile expects the first nine items in a customized dialog box to have the same functions as the corresponding items in the StandardGetFile dialog box; CustomPutFile expects the first twelve items to have the same functions as the corresponding items in the StandardPutFile dialog box. If you want to eliminate one of the standard items from the display, leave it in the item list but place its coordinates outside the bounds of the dialog box rectangle.Listing 3-16 shows the dialog item list for the default Open dialog box, in Rez input format. The constant statements in the section “Writing a Dialog Hook Function” list which elements the items represent in the dialog boxes.The item list for the default Open dialog boxresource 'DITL'(-6042)                {    {                    {135, 252, 155, 332}, Button { enabled, "Open" },                    {104, 252, 124, 332}, Button { enabled, "Cancel" },                    {0, 0, 0, 0}, HelpItem { disabled, HMScanhdlg {-6042}},                    {8, 235, 24, 337}, UserItem { enabled },                    {32, 252, 52, 332}, Button { enabled, "Eject" },                    {60, 252, 80, 332}, Button { enabled, "Desktop" },                    {29, 12, 159, 230}, UserItem { enabled },                    {6, 12, 25, 230}, UserItem { enabled },                    {91, 251, 92, 333}, Picture  { disabled, 11 },                }    };Listing 3-17 shows the dialog item list for the default Save dialog box, in Rez input format.The item list for the default Save dialog boxresource 'DITL'(-6043)                {    {                    {161, 252, 181, 332}, Button { enabled, "Save" },                    {130, 252, 150, 332}, Button { enabled, "Cancel" },                    {0, 0, 0, 0}, HelpItem { disabled, HMScanhdlg {-6043}},                    {8, 235, 24, 337}, UserItem { enabled },                    {32, 252, 52, 332}, Button { enabled, "Eject" },                    {60, 252, 80, 332}, Button { enabled, "Desktop" },                    {29, 12, 127, 230}, UserItem { enabled },                    {6, 12, 25, 230}, UserItem { enabled },                    {119, 250, 120, 334}, Picture { disabled, 11 },                    {157, 15, 173, 227}, EditText { enabled, "" },                    {136, 15, 152, 227}, StaticText { disabled, "Save as:" },                    {88, 252, 108, 332}, UserItem { disabled },            }    };The third item in each list (HelpItem) supplies Apple’s Balloon Help for items in the dialog box. HelpItem specifies the resource ID of the 'hdlg' resource that contains the help strings for the standard dialog items. If you want to modify the help text of an existing dialog item, you should copy the original 'hdlg' resource from the System file into your application’s resource fork and modify the text in the copied resource as desired; then you must change the resource ID specified in the HelpItem to the resource ID of the copied and modified resource. To provide Balloon Help for your own items, supply a second 'hdlg' resource and reference it with another help item at the end of the list. The existing items retain their default text (unless you change that text, as described).The default dialog item lists used by the original Standard File Package routines do not contain help items, but the Standard File Package does provide Balloon Help when you call those routines in system software version 7.0 and later. If you call one of the original routines and the specified dialog item list does not contain any help items, the Standard File Package uses its default help text for the standard dialog items. If, however, the dialog item list does contain a help item, the Standard File Package assumes that your application provides the text for all help items, including the standard dialog items.For more information about Balloon Help, see the chapter “The Help Manager” of the Macintosh Toolbox volume.The default Standard File Package dialog boxes support color. The System file contains 'dctb' resources with the same resource IDs as the default dialog boxes, so that the Dialog Manager uses color grafPorts for the default dialog boxes. (See the chapter “The Dialog Manager” of the Macintosh Toolbox volume for a description of the 'dctb' resource.) If you create your own dialog boxes, include 'dctb' resources.<36pt\>\x12 <8bat\>uWriting a File Filter FunctionA file filter function determines which files appear in the display list when the user is opening a file. Both StandardGetFile and CustomGetFile recognize file filter functions.When the Standard File Package is displaying the contents of a volume or folder, it checks the file type of each file and filters out files whose types do not match your application’s specifications. (Your application can specify which file types are to be displayed through the typeList parameter to either StandardGetFile or CustomGetFile, as described in “Presenting the Standard User Interface” earlier in this chapter.) If your application also supplies a file filter function, the Standard File Package calls that function each time it identifies a file of an acceptable type.The file filter function receives a pointer to the file’s catalog information record (described in the File Manager chapter of this volume). It evaluates the catalog entry and returns a Boolean value that determines whether the file is filtered (that is, a value of TRUE suppresses display of the filename, and a value of FALSE allows the display). If you do not supply a file filter function, the Standard File Package displays all files of the specified types.A file filter function to be called by StandardGetFile must use this syntax:FUNCTION MyStandardFileFilter (pb: CInfoPBPtr): Boolean;The single parameter passed to your standard file filter function is the address of a catalog information parameter block; see the chapter “The File Manager” in this volume for a description of the fields of that parameter block.When CustomGetFile calls your file filter function, it can also receive a pointer to any data that you passed in through the call to CustomGetFile. A file filter function to be called by CustomGetFile must use this syntax:FUNCTION MyCustomFileFilter (pb: CInfoPBPtr; myDataPtr: Ptr):                                         Boolean;Listing 3-18 shows a sample file filter function to be called by CustomGetFile. You might define a file filter function like this to support the custom dialog box illustrated in Figure 3-17, which lists files of the type shown in the pop-up box.A sample file filter functionFUNCTION MyCustomFileFilter (pb: CInfoPBPtr; myDataPtr: Ptr): Boolean;BEGIN    MyCustomFileFilter := TRUE;                                                        {default: don’t show the file}    IF pb^.ioFlFndrInfo.fdType = gTypesArray[gCurrentType] THEN        MyCustomFileFilter := FALSE;                                                    {show the file}END;In Listing 3-18, the global variable gCurrentType contains the index in the array gTypesArray of the currently selected file type. If the type of a file passed in for evaluation matches the current file type, the filter returns FALSE, indicating that StandardGetFile should put it in the list. See Listing 3-19 for an example of how you can use a dialog hook function to change the value of gCurrentType according to user selections in the pop-up menu control.Writing a Dialog Hook FunctionA dialog hook function handles item selections in a dialog box. It receives a pointer to the dialog record and an item number from the ModalDialog procedure via the Standard File Package each time the user selects one of the dialog items. Your dialog hook function checks the item number of each selected item, and then either handles the selection or passes it back to the Standard File Package.If you provide a dialog hook function, CustomPutFile and CustomGetFile call your function immediately after calling ModalDialog. They pass your function the item number returned by ModalDialog, a pointer to the dialog record, and a pointer to the data received from your application, if any. The dialog hook function must use this syntax:FUNCTION MyDlgHook (item: Integer; theDialog: DialogPtr;                             myDataPtr: Ptr): Integer;Your dialog hook function returns as its function result an integer that is either the item number passed to it or some other item. If it returns one of the item numbers in the following list of constants, the Standard File Package handles the selected item as described later in this section. If your dialog hook function does not handle a selection, it should pass the item number back to the Standard File Package for processing by setting its return value equal to the item number.CONST {items that appear in both the Open and Save dialog boxes}    sfItemOpenButton                                =    1;            {Save or Open button}    sfItemCancelButton                                =    2;            {Cancel button}    sfItemBalloonHelp                                =    3;            {Balloon Help}    sfItemVolumeUser                                =    4;            {volume icon and name}    sfItemEjectButton                                =    5;            {Eject button}    sfItemDesktopButton                                =    6;            {Desktop button}    sfItemFileListUser                                =    7;            {display list}    sfItemPopUpMenuUser                                =    8;            {directory pop-up menu}    sfItemDividerLinePict                                =    9;            {dividing line between buttons}    {items that appear in Save dialog boxes only}    sfItemFileNameTextEdit                                =    10;            {filename field}    sfItemPromptStaticText                                =    11;            {filename prompt text area}    sfItemNewFolderUser                                =    12;            {New Folder button}You must write your own dialog hook function to handle any items you have added to the dialog box.The constants that represent disabled items (sfItemBalloonHelp, sfItemDividerLinePict, and sfItemPromptStaticText) have no effect, but they are defined in the header files for the sake of completeness.<36pt\>\x12 <8bat\>uThe Standard File Package also recognizes a number of constants that do not represent any actual item in the dialog list; these constants are known as pseudo-items. There are two kinds of pseudo-items:n    pseudo-items passed to your dialog hook function by the Standard File Packagen    pseudo-items passed to the Standard File Package by your dialog hook functionThe sfHookFirstCall constant is an example of the first kind of pseudo-item. The Standard File Package sends this pseudo-item to your dialog hook function immediately before it displays the dialog box. Your function typically reacts to this item number by performing any necessary initialization.You can pass back other pseudo-items to indicate that you’ve handled the user selection or to request some action by the Standard File Package. For example, if the list of files and folders must be rebuilt because of a user selection, you can pass back the pseudo-item sfHookRebuildList. Similarly, when your application handles the selection and needs no further action by the Standard File Package, it should return the sfHookNullEvent. When the Standard File Package receives either sfHookNullEvent or an item number that it doesn’t recognize from a dialog hook function, it does nothing.The Standard File Package recognizes these peudo-item numbers:CONST {pseudo-items available prior to version 7.0}    sfHookFirstCall                                =    -1;            {initialize display}    sfHookCharOffset                                =    $1000;            {offset for character input}    sfHookNullEvent                                =    100;            {null event}    sfHookRebuildList                                =    101;            {redisplay list}    sfHookFolderPopUp                                =    102;            {display parent-directory menu}    sfHookOpenFolder                                =    103;            {display contents of }                                                    { selected folder or volume}    {additional pseudo-items introduced in version 7.0}    sfHookLastCall                                =    -2;            {clean up after display}    sfHookOpenAlias                                =    104;            {resolve alias}    sfHookGoToDesktop                                =    105;            {display contents of desktop}    sfHookGoToAliasTarget                                =    106;            {select target of alias}    sfHookGoToParent                                =    107;            {display contents of parent}    sfHookGoToNextDrive                                =    108;            {display contents of next drive}    sfHookGoToPrevDrive                                =    109;            {display contents of previous drive}    sfHookChangeSelection                                =    110;            {select target of reply record}    sfHookSetActiveOffset                                =    200;            {switch active item}The Standard File Package uses a set of modal-dialog filter functions (described in the following section) to map user actions during the dialog onto the defined item numbers. Some of the mapping is indirect. A click of the Open button, for example, is mapped to sfItemOpenButton only if a file is selected in the display list. If a folder or volume is selected, the Standard File Package maps the selection onto the pseudo-item sfHookOpenFolder.The lists that follow summarize when various items and pseudo-items are generated and how they are handled. The descriptions indicate the simplest mouse action that generates each item; many of the items can also be generated by keyboard actions, as described earlier in “Keyboard Equivalents.” Any indicated effects of passing back these constants do not occur until the Standard File Package receives the constant back from your dialog hook function.<36pt\>\x12 <8bat\>uConstant descriptionssfItemOpenButton    Generated when the user clicks Open or Save while a filename is selected. The Standard File Package fills in the reply record (setting sfGood to TRUE), removes the dialog box, and returns.sfItemCancelButton    Generated when the user clicks Cancel. The Standard File Package sets sfGood to FALSE, removes the dialog box, and returns.sfItemVolumeUser    Generated when the user clicks the volume icon or its name. The Standard File Package rebuilds the display list to show the contents of the folder that is one level up the hierarchy (that is, the parent directory of the current parent directory).sfItemEjectButton    Generated when the user clicks Eject. The Standard File Package ejects the volume that is currently selected.sfItemDesktopButton     Generated when the user clicks the Drive button in a customized dialog box defined by one of the earlier procedures. You never receive this item number with the new procedures; when the user clicks the Desktop button, the action is mapped to the item sfHookGoToDesktop, described later in this section. The Standard File Package displays the contents of the next drive.sfItemFileListUser    Generated when the user clicks an item in the display list. The Standard File Package updates the selection and generates this item for your information.sfItemPopUpMenuUser    Never generated. The Standard File Package’s modal-dialog filter function maps clicks on the directory pop-up menu to sfHookFolderPopUp, described later in this section.sfItemFileNameTextEdit    Generated when the user clicks in the filename field. TextEdit and the Standard File Package process mouse clicks in the filename field, but the item number is generated for your information.sfItemNewFolderUser    Generated when the user clicks New Folder. The Standard File Package displays the New Folder dialog box.The pseudo-items are messages that allow your application and the Standard File Package to communicate and support various features added since the original design of the Standard File Package.The Standard File Package generates three pseudo-items that give your application the chance to control a customized display.Constant descriptionssfHookFirstCall    Generated by the Standard File Package as a signal to your dialog hook function that it is about to display a dialog box. If you want to initialize the display, do so when you receive this item. You can specify the current directory either by returning sfHookGoToDesktop or by changing the reply record and returning sfHookChangeSelection.sfHookLastCall    Generated by the Standard File Package as a signal to your dialog hook function that it is about to remove a dialog box. If you created any structures when the dialog box was first displayed, remove them when you receive this item.sfHookNullEvent     Issued periodically by the Standard File Package if no user action has taken place. Your application can use this null event to perform any updating or periodic processing that might be necessary.Your application can generate three pseudo-items to request services from the Standard File Package.Constant descriptionssfHookRebuildList    Returned by your dialog hook function to the Standard File Package when it needs to redisplay the file list. Your application might need to redisplay the list if, for example, it allows the user to change the file types to be displayed. The Standard File Package rebuilds and displays the list of files that can be opened.sfHookChangeSelection    Returned by your application to the Standard File Package after your application changes the reply record so that it describes a different file or folder. (You’ll need to pass the address of the reply record in the yourDataPtr field if you want to do this.) The Standard File Package rebuilds the display list to show the contents of the folder or volume containing the object described in the reply record. It selects the item described in the reply record.sfHookSetActiveOffset    Your application adds this constant to an item number and sends the result to the Standard File Package. The Standard File Package activates that item in the dialog box, making it the target of keyboard input. This constant allows your application to activate a specific field in the dialog box without explicit input from the user.The Standard File Package’s own modal-dialog filter functions generate a number of pseudo-items that allow its dialog hook functions to support various features introduced since the original design of the standard file dialog boxes. Except under extraordinary circumstances, your dialog hook function always passes any of these item numbers back to the Standard File Package for processing.Constant descriptionssfHookCharOffset    The Standard File Package adds this constant to the value of an ASCII character when it’s using keyboard input for item selection. The Standard File Package uses the decoded ASCII character to select an entry in the display list.sfHookFolderPopUp    Generated when the user clicks the directory pop-up menu. The Standard File Package displays the pop-up menu showing all parent directories.sfHookOpenFolder    Generated when the user clicks the Open button while a folder or volume is selected in the display list. The Standard File Package rebuilds the display list to show the contents of the folder or volume.sfHookOpenAlias    Generated by the Standard File Package as a signal that the selected item is an alias for another file, folder, or volume. If the selected item is an alias for a file, the Standard File Package resolves the alias, places the file system specification record of the target in the reply record, and returns.     If the selected item is an alias for a folder or volume, the Standard File Package resolves the alias and rebuilds the display list to show the contents of the alias target.sfHookGoToDesktop    Generated when the user clicks the Desktop button. The Standard File Package displays the contents of the desktop in the display list.sfHookGoToAliasTarget    Generated when the user presses the Option key while opening an item that is an alias. The Standard File Package rebuilds the display list to display the volume or folder containing the alias target and selects the target.sfHookGoToParent    Generated when the user presses Command–Up Arrow (or clicks on the volume icon). The Standard File Package rebuilds the display list to show the contents of the folder that is one level up the hierarchy (that is, the parent directory of the current parent directory).sfHookGoToNextDrive    Generated when the user presses Command–Right Arrow. The Standard File Package displays the contents of the next volume.sfHookGoToPrevDrive    Generated when the user presses Command–Left Arrow. The Standard File Package displays the contents of the previous volume.The CustomGetFile and CustomPutFile procedures call your dialog hook function for item selections in both the main dialog box and any subsidiary dialog boxes (such as the dialog box for naming a new folder while saving a document through CustomPutFile). To determine whether the dialog record describes the main dialog box or a subsidiary dialog box, check the value of the refCon field in the window record in the dialog record.Prior to system software version 7.0, the Standard File Package did not call your dialog hook function during subsidiary dialog boxes. Dialog hook functions for the new CustomGetFile and CustomPutFile procedures must check the dialog window’s refCon field to determine the target of the dialog record.<36pt\>\x12 <8bat\>uThe defined values for the refCon field represent the Standard File dialog boxes.CONST                sfMainDialogRefCon                                =    'stdf';            {main dialog box}                sfNewFolderDialogRefCon                                =    'nfdr';            {New Folder dialog box}                sfReplaceDialogRefCon                                 =    'rplc';            {name conflict dialog box}                sfStatWarnDialogRefCon                                =    'stat';            {stationery warning}                sfErrorDialogRefCon                                =    'err ';            {general error report}                sfLockWarnDialogRefCon                                =    'lock';            {software lock warning}Constant descriptionssfMainDialogRefCon    The main dialog box, either Open or Save.sfNewFolderDialogRefCon    The New Folder dialog box.sfReplaceDialogRefCon    The dialog box requesting verification for replacing a file of the same name.sfStatWarnDialogRefCon    The dialog box warning that the user is opening the master copy of a stationery pad, not a piece of stationery.sfErrorDialogRefCon    A dialog box reporting a general error.sfLockWarnDialogRefCon    The dialog box warning that the user is opening a locked file and won’t be allowed to save any changes.Listing 3-19 defines a dialog hook function that handles user selections in the customized Open dialog box illustrated in Figure 3-17. Note that this dialog hook function handles selections only in the main dialog box, not in any subsidiary dialogs.A sample dialog hook functionFUNCTION MyDlgHook (item: Integer; theDialog: DialogPtr; myDataPtr: Ptr):                         Integer;VAR    myType:                    Integer;                    {menu item selected}    myHandle:                    Handle;                    {needed for GetDItem}    myRect:                    Rect;                    {needed for GetDItem}    myIgnore:                    Integer;                    {needed for GetDItem; ignored}CONST    kMyPopUpItem                 =    10;                    {item number of File Type pop-up menu}BEGIN    MyDlgHook := item;                                        {by default, return the item passed in}    IF GetWRefCon(WindowPtr(theDialog)) <> LongInt(sfMainDialogRefCon) THEN        Exit(MyDlgHook);                                    {this function is only for main dialog}    {do processing of pseudo-items and our own additional item}    CASE item OF         sfHookFirstCall:                                    {pseudo-item: first time function called}            BEGIN                GetDItem(theDialog, kPopUpItem, myType, myHandle, myRect);                    SetCtlValue(ControlHandle(myHandle), gCurrentType);                MyDlgHook := sfHookNullEvent;            END;        kMyPopUpItem:                                    {user hit on File Type pop-up menu}            BEGIN                GetDItem(theDialog, item, myIgnore, myHandle, myRect);                    myType := GetCtlValue(ControlHandle(myHandle));                IF myType <> gCurrentType THEN                    BEGIN                        gCurrentType := myType;                        MyDlgHook := sfHookRebuildList;                    END;            END;        OTHERWISE            ;                                {ignore all other items}    END;END;The pop-up menu is stored as a control in the application’s resource fork. Values stored in the resource determine the appearance of the control, such as the pop-up title text and the menu associated with the control. The ModalDialog procedure takes care of drawing the box around the pop-up menu and the title of the dialog box. When the dialog hook function is first called, it simply retrieves a handle to that control and sets the value of the pop-up control to the current menu item (stored in the global variable gCurrentType). MyDlgHook then returns sfHookNullEvent to indicate that no further processing is required.When the user clicks the pop-up menu control, ModalDialog calls the standard control definition function associated with it. If the user makes a selection in the pop-up menu, MyDlgHook is called with the item parameter equal to kPopUpItem. Your dialog hook function needs simply to determine the current value of the control and respond accordingly. In this case, if the user has selected a new file type, the global variable gCurrentType is updated to reflect the new selection, and MyDlgHook returns sfHookRebuildList to cause the Standard File Package to rebuild the list of files and folders displayed in the dialog box.For complete details on handling pop-up menus, see the chapters “The Control Manager” and “The Menu Manager” in the Macintosh Toolbox volume.Writing a Modal-Dialog Filter FunctionA modal-dialog filter function controls events closer to their source by filtering the events received from the Event Manager. The Standard File Package itself contains an internal modal-dialog filter function that maps keypresses and other user input onto the equivalent dialog box items. If you also want to process events at this level, you can supply your own filter function.You can supply a modal-dialog filter function only when you use one of the procedures that displays a customized dialog box (that is, CustomGetFile, CustomPutFile, SFPGetFile, or SFPPutFile).<36pt\>\x12 <8bat\>uYour modal-dialog filter function determines how the Dialog Manager procedure ModalDialog filters events. ModalDialog retrieves events by calling the Event Manager function GetNextEvent. As just indicated, the Standard File Package contains an internal filter function that performs some preliminary processing on each event it receives. If you provide a modal-dialog filter function, ModalDialog calls your filter function after it calls the internal Standard File Package filter function and before it sends the event to your dialog hook function.You might provide a modal-dialog filter function for several reasons. If you have customized the Open or Save dialog boxes by adding one or more items, you might want to map some of the user’s keypresses to those items in the same way that the internal filter function maps certain keypresses to existing items.Another reason to provide a modal-dialog filter function is to avoid a problem that can arise if an update event is received for one of your application’s windows while a Standard File Package dialog box is displayed.The problem described in the following paragraph occurs only in system software versions earlier than version 7.0. The internal modal-dialog filter function installed by the Standard File Package when running in version 7.0 and later avoids the problem by passing the update event to your dialog filter and, if your filter doesn’t handle the event, mapping it to a null event.<36pt\>\x12 <8bat\>uWhen ModalDialog calls GetNextEvent and receives the update event, ModalDialog does not know how to respond to it and therefore passes the update event to the Standard File Package’s internal filter function. The internal filter function cannot handle the update event either. As a result, if you do not provide your own modal-dialog filter function that knows how to handle the update event, that event is never cleared. The next time ModalDialog calls GetNextEvent, it receives the same update event. ModalDialog never receives a null event, so any processing your dialog hook function performs in response to the sfHookNullEvent pseudo-item is never performed. You can solve this problem by providing a modal-dialog filter function that handles the update event or changes it into a null event. See Listing 3-20 for details.A modal-dialog filter function used with SFPGetFile and SFPPutFile is declared like any filter function passed to ModalDialog. Your function is passed a pointer to the dialog record, a pointer to the event record, and the item number. (The modal-dialog filter function is described in the chapter “The Dialog Manager” of the Macintosh Toolbox volume.) FUNCTION MyModalFilter (theDialog: DialogPtr;                                 VAR theEvent: EventRecord;                                 VAR itemHit: Integer): Boolean;The modal-dialog filter function used with CustomGetFile and CustomPutFile requires an additional parameter, a pointer to the data received from your application, if any.FUNCTION MyModalFilterYD (theDialog: DialogPtr;                                     VAR theEvent: EventRecord;                                     VAR itemHit: Integer;                                     myDataPtr: Ptr): Boolean;Your modal-dialog filter function returns a Boolean value that reports whether it handled the event. If your function returns a value of FALSE, ModalDialog processes the event through its own filters. If your function returns a value of TRUE, ModalDialog returns with no further action.The CustomGetFile and CustomPutFile procedures call your filter function to process events in both the main dialog box and any subsidiary dialog boxes (such as the dialog box for naming a new folder while saving a document through CustomPutFile). To determine whether the dialog record describes the main dialog box or a subsidiary dialog box, check the value of the refCon field in the window record in the dialog record, as described earlier in “Writing a Dialog Hook Function.”Listing 3-20 shows how to define a modal-dialog filter function that prevents update events from clogging the event queue.A sample modal-dialog filter functionFUNCTION MyModalFilter (theDialog: DialogPtr; VAR theEvent: EventRecord;                                VAR itemHit: Integer): Boolean;BEGIN    MyModalFilter := FALSE;                                                {we haven’t handled the event yet}    IF theEvent.what = updateEvt THEN        IF IsAppWindow(WindowPtr(theEvent.message)) THEN            BEGIN                DoUpdateEvent(WindowPtr(theEvent.message));                    MyModalFilter := TRUE;                                    {we have handled the event}            END;END;If this filter function receives an update event for a window other than the Standard File Package dialog box, it calls the application’s routine for handling update events  (DoUpdateEvent) and returns TRUE to indicate that the event has been handled. See the chapters “The Event Manager” and “The Window Manager” in the Macintosh Toolbox volume for complete details on handling update events.Writing an Activation ProcedureThe activation procedure controls the highlighting of dialog items that are defined by your application and can receive keyboard input. Ordinarily, you need to supply an activation procedure only if your application builds a list from which the user can select entries. The Standard File Package supplies the activation procedure for the file display list and for all TextEdit fields. You can also use the activation procedure to keep track of which field is receiving keyboard input, if your application needs that information. The target of keyboard input is called the active field. The two standard keyboard-input fields are the filename field (present only in Save dialog boxes) and the display list. Unless you override it through your own dialog hook function, the Standard File Package handles the highlighting of its own items and TextEdit fields. When the user changes the keyboard target by pressing the mouse button or the Tab key, the Standard File Package calls your activation procedure twice: the first call specifies which field is being deactivated, and the second specifies which field is being activated. Your application is responsible for removing the highlighting when one of its fields becomes inactive and for adding the highlighting when one of its fields becomes active. The Standard File Package can handle the highlighting of all TextEdit fields, even those defined by your application.The activation procedure receives four parameters: a dialog pointer, a dialog item number, a Boolean value that specifies whether the field is being activated (TRUE) or deactivated (FALSE), and a pointer to your own data.PROCEDURE MyActivateProc (theDialog: DialogPtr; itemNo: Integer;                                    activating: Boolean; myDataPtr: Ptr);Setting the Current DirectoryThe first time your application calls one of the Standard File Package routines, the default current directory (that is, the directory whose contents are listed in the dialog box) is determined by the way in which your application was launched.n    If the user launched your application directly (perhaps by double-clicking its icon in the Finder), the default directory is the directory in which your application is located.n    If the user launched your application indirectly (perhaps by double-clicking one of your application’s document icons) the default directory is the directory in which that document is located.Every subsequent time your application calls one of the Standard File Package routines, the default current directory is simply the directory that was current when the user completed the previous dialog box.If necessary, you can change the default current directory. For example, when the user needs to select a dictionary file for a spell-checking application, the application might set the current directory to a directory containing document-specific dictionary files. This saves the user from having to navigate the directory hierarchy from the directory containing documents to that containing dictionary files.Most applications shouldn’t need to alter the default current directory.<36pt\>\x12 <8bat\>uIf you are using the enhanced Standard File Package routines, you can set the current directory by filling in the fields of the file system specification in the reply record passed to CustomGetFile or CustomPutFile. You do this within your dialog hook function. Listing 3-21 defines a dialog hook function that makes the currently active System folder be the current directory.Setting the current directoryFUNCTION MyDlgHook (item: Integer; theDialog: DialogPtr; myDataPtr: Ptr):                         Integer;VAR    myReplyPtr:                    StandardFileReplyPtr;    foundVRefNum:                    Integer;    foundDirID:                    LongInt;    myErr:                    OSErr;BEGIN    MyDlgHook := item;                                        {by default, return the item passed in}    IF GetWRefCon(WindowPtr(theDialog)) <> LongInt(sfMainDialogRefCon) THEN        Exit(MyDlgHook);                                    {this function is only for main dialog}    CASE item OF            sfHookFirstCall:                                    {pseudo-item: first time function called}            BEGIN                myReplyPtr := StandardFileReplyPtr(myDataPtr);                    myErr := FindFolder(kOnSystemDisk, kSystemFolderType,                                     kDontCreateFolder, foundVRefNum, foundDirID);                IF myErr = noErr THEN                    BEGIN                        myReplyPtr^.sfFile.parID := foundDirID;                        myReplyPtr^.sfFile.vRefNum := foundVRefNum;                        MyDlgHook := sfHookChangeSelection;                    END;            END;        OTHERWISE            ;                                {ignore all other items}    END;END;This dialog hook function installs the System Folder’s volume reference number and parent directory ID into the file system specification whose address is passed in the myDataPtr parameter. Because the dialog hook function returns the constant sfHookChangeSelection the first time it is called (that is, in response to the sfHookFirstCall pseudo-item), the Standard File Package sets the current directory to the indicated directory when the dialog box is displayed.Using the Original ProceduresThe Standard File Package still recognizes all procedures available before system software version 7.0 (SFGetFile, SFPutFile, SFPGetFile, and SFPPutFile). It displays the new interface for all applications that don’t customize the dialog boxes in incompatible ways (that is, applications that specify both the dialog hook and the modal-dialog filter pointers as NIL and that specify no alternative dialog ID).When the Standard File Package can’t use the enhanced dialog box layout because an application customized the dialog box with the earlier procedures, it nevertheless makes some changes to the display:n    It changes the label of the Drive button to Desktop and makes the desktop the root of the display.n    It moves the volume icon slightly to the right, to make room for selection highlighting around the display list field.If, however, a customized dialog box has suppressed the file display list (by specifying coordinates outside of the dialog box), the Standard File Package uses the earlier interface, on the assumption that the dialog box is designed for volume selection.If you need to use the procedures available before system software version 7.0, you need to be aware of a number of differences between those procedures and the enhanced procedures. The remainder of this section summarizes the most important differences.n    The original procedures do not recognize some pseudo-items under previous system software versions. For example, the pseudo-item sfHookLastCall is not used before version 7.0. See the comments under “Constants” in the section “Summary” for information on which pseudo-items are universally available.n    The original standard file reply record (type SFReply) returns a working directory reference number, not a volume reference number. Typically you should immediately convert that number to a volume reference number and directory ID using GetWDInfo or PBGetWDInfo.n    Dialog hook functions used with the original procedures are not passed a myDataPtr parameter.Reference to the Standard File PackageThis section describes the data structures and routines that are specific to the Standard File Package. The “Data Structures” section shows the Pascal data structures for the original and the enhanced Standard File reply records. The “Routines” section describes routines for opening and saving files.Data StructuresThe Standard File Package exchanges information with your application using a standard file reply record. If you use the procedures introduced in system software version 7.0, you use a reply record of type StandardFileReply. If you use the procedures available before version 7.0, you must a reply record of type SFReply.Enhanced Standard File Reply RecordWhen you use one of the procedures StandardPutFile, StandardGetFile, CustomPutFile, or CustomGetFile, you pass a reply record of type StandardFileReply.TYPE StandardFileReply =RECORD    sfGood:                    Boolean;                {TRUE if user did not cancel}    sfReplacing:                    Boolean;                {TRUE if replacing file with same name}    sfType:                    OSType;                {file type}    sfFile:                    FSSpec;                {selected file, folder, or volume}    sfScript:                    ScriptCode;                {script of file, folder, or volume name}    sfFlags:                    Integer;                {Finder flags}    sfIsFolder:                    Boolean;                {selected item is a folder}    sfIsVolume:                    Boolean;                {selected item is a volume}    sfReserved1:                    LongInt;                {reserved}    sfReserved2:                    Integer;                {reserved}END;sfGood    Reports whether the reply record is valid. The value is TRUE after the user clicks Save or Open; FALSE after the user clicks Cancel. When the user has completed the dialog box, the other fields in the reply record are valid only if the sfGood field contains TRUE.sfReplacing    Reports whether a file to be saved replaces an existing file of the same name. This field is valid only after a call to the StandardPutFile or CustomPutFile procedure. When the user assigns a name that duplicates that of an existing file, the Standard File Package asks for verification by displaying a subsidiary dialog box (illustrated in Figure 3-14). If the user verifies the name, the Standard File Package sets the sfReplacing field to TRUE and returns to your application; if the user cancels the overwriting of the file, the Standard File Package returns to the main dialog box. If the name does not conflict with an existing name, the Standard File Package sets the field to FALSE and returns.sfType    Contains the file type of the selected file. (File types are described in the chapter “The Finder Interface” of the Toolbox volume.) Only StandardGetFile and CustomGetFile return a file type in this field.sfFile    Describes the selected file, folder, or volume with a file system specification record, which contains a volume reference number, parent directory ID, and name. (See the chapter “The File Manage” in this volume for a complete description of the file system specification record.) If the selected item is an alias for another item, the Standard File Package resolves the alias and places the file system specification record for the target in the sfFile field when the user completes the dialog box. If the selected file is a stationery pad, the reply record describes the file itself, not a copy of the file.sfScript    Identifies the script in which the name of the document is to be displayed. (This information is used by the Finder and by the Standard File Package. See the chapter “The Script Manager” of the Worldwide Software volume for a list of defined script codes.) A script code of smSystemScript (–1) represents the default system script.sfFlags    Contains the Finder flags from the Finder information record in the catalog entry for the selected file. (See the chapter “The Finder Interface” in the Toolbox volume for a description of the Finder flags.) This field is returned only by StandardGetFile and CustomGetFile. If your application supports stationery, it should check the stationery bit in the Finder flags to determine whether to treat the selected file as stationery. Unlike the Finder, the Standard File Package does not automatically create a document from a stationery pad and pass your application the new document. If the user opens a stationery document from within an application that does not support stationery, the Standard File Package displays a dialog box warning the user that the master copy is being opened.sfIsFolder    Reports whether the selected item is a folder (TRUE) or a file or volume (FALSE). This field is meaningful only during the execution of a dialog hook function.sfIsVolume    Reports whether the selected item is a volume (TRUE) or a file or folder (FALSE). This field is meaningful only during the execution of a dialog hook function.sfReserved1    Reserved.sfReserved2    Reserved.Original Standard File Reply RecordWhen you use one of the procedures SFPutFile, SFGetFile, SFPPutFile, or SFPGetFile, you pass a reply record of type SFReply.SFReply =RECORD                good:                Boolean;                {TRUE if user did not cancel}                copy:                Boolean;                {reserved}                fType:                OSType;                {file type}                vRefNum:                Integer;                {working directory reference number}                version:                Integer;                {reserved}                fName:                Str63;                {filename}END;good    Reports whether the reply record is valid. The value is TRUE after the user clicks Save or Open; FALSE after the user clicks Cancel. When the user has completed the dialog box, the other fields in the reply record are valid only if the value of good is TRUE.copy    Reserved.fType    Contains the file type of the selected file. (File types are described in the chapter “The Finder Interface” of the Toolbox volume.) Only SFGetFile and SFPGetFile return a file type in this field.vRefNum    Contains the working directory reference number of the selected file.version    Reserved.fName    Contains the name of the selected file.In spite of its name, the vRefNum field does not contain a volume reference number. Instead, it contains a working directory reference number, which encodes both the volume reference number and the parent directory ID of the selected file. You can obtain the volume reference number and directory ID of the file by calling GetWDInfo or PBGetWDInfo. See the chapter “The File Manager” in this volume for details about working directory reference numbers.<36pt\>\x12 <8bat\>uRoutinesThis section describes the routines you can use to prompt the user for a file’s name and location when saving or opening a file. If your application is designed to run in system software versions prior to version 7.0, you must use either SFGetFile or SFPGetFile when opening a file and either SFPutFile or SFPPutFile when saving a file.If your application is designed to take advantage of features introduced in system software version 7.0 or later, you can use the new routines intended to simplify the code required to elicit a filename from the user. The StandardPutFile and StandardGetFile procedures are simplified versions of the original procedures for handling the user interface when storing and retrieving files. The CustomPutFile and CustomGetFile procedures are customizable versions of the same procedures.Saving FilesYou can use the StandardPutFile procedure to present the standard user interface when the user asks to save a file. If you need to add elements to the default dialog boxes or exercise greater control over user actions in the dialog box, use CustomPutFile.If your application is designed to execute in system software versions earlier than version 7.0, you can use the corresponding procedures SFPutFile and SFPPutFile. 3StandardPutFileYou can use the StandardPutFile procedure to display the default Save dialog box when the user is saving a file.PROCEDURE StandardPutFile (prompt: Str255; defaultName: Str255;                                    VAR reply: StandardFileReply);prompt    The prompt message to be displayed over the text field.defaultName    The initial name of the file..reply    The reply record, which StandardPutFile fills in before returning.DESCRIPTIONStandardPutFile presents a dialog box through which the user specifies the name and location of a file to be written to. The dialog box is centered on the screen. While the dialog box is active, StandardPutFile gets and handles events until the user completes the interaction, either by selecting a name and authorizing the save or by canceling the save. The StandardPutFile procedure returns the user’s input in a standard file reply record.SPECIAL CONSIDERATIONSStandardPutFile is not available in all versions of system software. Use the Gestalt function to determine whether StandardPutFile is available before calling it.The StandardPutFile procedure may move memory; your application should not call it at interrupt time.3CustomPutFileUse the CustomPutFile procedure when your application requires more control over the Save dialog box than is possible using StandardPutFile.PROCEDURE CustomPutFile (prompt: Str255; defaultName: Str255;                                     VAR reply: StandardFileReply;                                     dlgID: Integer; where: Point;                                     dlgHook: DlgHookYDProcPtr;                                     filterProc: ModalFilterYDProcPtr;                                    activeList: Ptr;                                     activateProc: ActivateYDProcPtr;                                    yourDataPtr: UNIV Ptr);prompt    The prompt message to be displayed over the text field.defaultName    The initial name of the file.reply    The reply record, which CustomPutFile fills in before returning.dlgID    The resource ID of a customized dialog template. To use the standard template, set this parameter to 0.where    The upper-left corner of the dialog box, in global coordinates. If you specify the point (–1,–1), CustomPutFile automatically centers the dialog box on the screen.    dlgHook    A pointer to your dialog hook function, which handles item selections received from the Dialog Manager. Specify a value of NIL if you have not added any items to the dialog box and want the standard items handled in the standard ways. See “Writing a Dialog Hook Function” earlier in this chapter for a description of the dialog hook function.filterProc    A pointer to your modal-dialog filter function, which determines how the ModalDialog procedure filters events when called by the CustomPutFile procedure. Specify a value of NIL if you are not supplying your own function. See “Writing a Modal-Dialog Filter Function” earlier in this chapter for a description of the modal-dialog filter function.activeList    A pointer to a list of all items in the dialog box that can be activated—that is, can be the target of keyboard input. If you supply an activeList parameter of NIL, CustomPutFile uses the default targets (the filename field and the list of files and folders). If you have added any fields that can accept keyboard input, you must modify the list. The list is stored as an array of 16-bit integers. The first integer is the number of items in the list. The remaining integers are the item numbers of all possible keyboard targets, in the order that they are activated by the Tab key.activateProc    A pointer to your activation procedure, which controls the highlighting of dialog items that are defined by your application and that can receive keyboard input. See “Writing an Activation Procedure” earlier in this chapter for a description of the activation procedure.yourDataPtr    Any 4-byte value; usually, a pointer to optional data supplied by your application. When CustomPutFile calls any of your callback routines, it adds this parameter, making the data available to your callback routines. If you are not supplying any data of your own, you can specify a value of NIL.DESCRIPTIONCustomPutFile is an alternative to StandardPutFile when you want to display a customized Save dialog box or handle the default dialog box in a customized way. During the dialog, CustomPutFile gets and handles events (possibly with the assistance of application-defined callback routines) until the user completes the interaction, either by selecting a name and authorizing the save or by canceling the save. CustomPutFile returns the user’s input in a standard file reply record. SPECIAL CONSIDERATIONSCustomPutFile is not available in all versions of system software. Use the Gestalt function to determine whether CustomPutFile is available before calling it.CustomPutFile may move memory; your application should not call it at interrupt time.3SFPutFileUse the SFPutFile procedure to display the standard Save dialog box when the user is saving a file.PROCEDURE SFPutFile (where: Point; prompt: Str255;                            origName: Str255; dlgHook: DlgHookProcPtr;                            VAR reply: SFReply);where    The upper-left corner of the dialog box, in global coordinates.prompt    The prompt message to be displayed over the text field.origName    The initial name of the file.dlgHook    A pointer to your dialog hook function, which handles item selections received from the Dialog Manager. Specify a value of NIL if you want the standard items handled in the standard ways. See “Writing a Dialog Hook Function” earlier in this chapter for a description of the dialog hook function.reply    The reply record, which SFPutFile fills in before returning.DESCRIPTIONSFPutFile presents a dialog box through which the user specifies the name and location of a file to be written to. During the dialog, SFPutFile gets and handles events until the user completes the interaction, either by selecting a name and authorizing the save or by canceling the save. The SFPutFile procedure returns the user’s input in a standard file reply record.SPECIAL CONSIDERATIONSSFPutFile may move memory; your application should not call it at interrupt time.3SFPPutFileUse the SFPPutFile procedure when your application requires more control over the Save dialog box than is possible using SFPutFile.PROCEDURE SFPPutFile (where: Point; prompt: Str255;                                origName: Str255; dlgHook: DlgHookProcPtr;                                VAR reply: SFReply; dlgID: Integer;                                filterProc: ModalFilterProcPtr);where    The upper-left corner of the dialog box, in global coordinates.prompt    The prompt message to be displayed over the text field.origName    The initial name of the file, if any.dlgHook    A pointer to your dialog hook function, which handles item selections received from the Dialog Manager. Specify a value of NIL if you have not added any items to the dialog box and want the standard items handled in the standard ways. See “Writing a Dialog Hook Function” earlier in this chapter for a description of the dialog hook function.reply    The reply record, which SFPPutFile fills in before returning.dlgID    The resource ID of a customized dialog template. To use the standard template, set this parameter to –3999.filterProc    A pointer to your modal-dialog filter function, which determines how the ModalDialog procedure filters events when called by the SFPPutFile procedure. Specify a value of NIL if you are not supplying your own function. See “Writing a Modal-Dialog Filter Function” earlier in this chapter for a description of the modal-dialog filter function.DESCRIPTIONSFPPutFile is an alternative to SFPutFile when you want to display a customized Save dialog box or handle the default dialog box in a customized way. During the dialog, SFPPutFile gets and handles events (possibly with the assistance of application-defined callback routines) until the user completes the interaction, either by selecting a name and authorizing the save or by canceling the save. SFPPutFile returns the user’s input in a standard file reply record. SPECIAL CONSIDERATIONSSFPPutFile may move memory; your application should not call it at interrupt time.Opening FilesYou can use the StandardGetFile procedure to present the standard user interface when the user asks to open a file. If you need to add elements to the default dialog boxes or exercise greater control over user actions in the dialog box, use CustomGetFile.If your application is designed to execute in system software versions earlier than version 7.0, you can use the corresponding procedures SFGetFile and SFPGetFile. 3StandardGetFileUse the StandardGetFile procedure to display the default Open dialog box when the user is opening a file.PROCEDURE StandardGetFile (fileFilter: FileFilterProcPtr;                                    numTypes: Integer;                                     typeList: SFTypeList;                                     VAR reply: StandardFileReply);fileFilter    A pointer to an optional file filter function, provided by your application, through which StandardGetFile passes files of the specified types.numTypes    The number of file types to be displayed. If you specify a numTypes value of –1, the first filtering passes files of all types.typeList    A list of file types to be displayed.reply    The reply record, which StandardGetFile fills in before returning.DESCRIPTIONStandardGetFile presents a dialog box through which the user specifies the name and location of a file to be opened. While the dialog box is active, StandardGetFile gets and handles events until the user completes the interaction, either by selecting a file to open or by canceling the operation. StandardGetFile returns the user’s input in a standard file reply record.The fileFilter, numTypes, and typeList parameters together determine which files appear in the display list. The first filtering is by file type, which you specify in the numTypes and typeList parameters. The numTypes parameter specifies the number of file types to be displayed. You can specify one or more types. If you specify a numTypes value of –1, the first filtering passes files of all types.The fileFilter parameter points to an optional file filter function, provided by your application, through which StandardGetFile passes files of the specified types. See “Writing a File Filter Function” earlier in this chapter for a description of the file filter function.SPECIAL CONSIDERATIONSStandardGetFile is not available in all versions of system software. Use the Gestalt function to determine whether StandardGetFile is available before calling it.StandardGetFile may move memory; your application should not call it at interrupt time.3CustomGetFileCall the CustomGetFile procedure when your application requires more control over the Open dialog box than is possible using StandardGetFile.PROCEDURE CustomGetFile (fileFilter: FileFilterYDProcPtr;                                    numTypes: Integer;                                     typeList: SFTypeList;                                     VAR reply: StandardFileReply;                                     dlgID: Integer; where: Point;                                     dlgHook: DlgHookYDProcPtr;                                     filterProc: ModalFilterYDProcPtr;                                    activeList: Ptr;                                     activateProc: ActivateYDProcPtr;                                    yourDataPtr: UNIV Ptr);fileFilter    A pointer to an optional file filter function, provided by your application, through which CustomGetFile passes files of the specified types.numTypes    The number of file types to be displayed. If you specify a numTypes value of –1, the first filtering passes files of all types.typeList    A list of file types to be displayed.reply    The reply record, which CustomGetFile fills in before returning.dlgID    The resource ID of a customized dialog template. To use the standard template, set this parameter to 0.where    The upper-left corner of the dialog box in global coordinates. If you specify the point (–1,–1), CustomGetFile automatically centers the dialog box on the screen.dlgHook    A pointer to your dialog hook function, which handles item hits received from the Dialog Manager. Specify a value of NIL if you have not added any items to the dialog box and want the standard items handled in the standard ways. See “Writing a Dialog Hook Function” earlier in this chapter for a description of the dialog hook function.filterProc    A pointer to your modal-dialog filter function, which determines how ModalDialog filters events when called by CustomGetFile. Specify a value of NIL if you are not supplying your own function. See “Writing a Modal-Dialog Filter Function” earlier in this chapter for a description of the modal-dialog filter function.activeList    A pointer to a list of all items in the dialog box that can be activated—that is, made the target of keyboard input. The list is stored as an array of 16-bit integers. The first integer is the number of items in the list. The remaining integers are the item numbers of all possible keyboard targets, in the order that they are activated by the Tab key. If you supply an activeList parameter of NIL, CustomGetFile directs all keyboard input to the displayed list.activateProc    A pointer to your activation procedure, which controls the highlighting of dialog items that are defined by your application and that can receive keyboard input. See “Writing an Activation Procedure” earlier in this chapter for a description of the activation procedure.yourDataPtr    A pointer to optional data supplied by your application.When CustomGetFile calls any of your callback routines, it pushes this parameter on the stack, making the data available to your callback routines. If you are not supplying any data of your own, specify a value of NIL.DESCRIPTIONCustomGetFile is an alternative to StandardGetFile when you want to use a customized dialog box or handle the default Open dialog box in a customized way.The first four parameters are similar to the same parameters in StandardGetFile. The fileFilter, numTypes, and typeList parameters determine which files appear in the list of choices. If you specify a value of –1 in the numTypes parameter, CustomGetFile displays or passes to your file filter function all files and folders at the current level of the display hierarchy, not just the files. If you provide a filter function, CustomGetFile passes it both the pointer to the catalog entry for each file to be processed and also a pointer to the optional data passed by your application in its call to CustomGetFile.SPECIAL CONSIDERATIONSCustomGetFile is not available in all versions of system software. Use the Gestalt function to determine whether CustomGetFile is available before calling it.CustomGetFile may move memory; your application should not call it at interrupt time.3SFGetFileUse the SFGetFile procedure to display the default Open dialog box when the user is opening a file.PROCEDURE SFGetFile (where: Point; prompt: Str255;                            fileFilter: FileFilterProcPtr;                            numTypes: Integer; typeList: SFTypeList;                            dlgHook: DlgHookProcPtr; VAR reply: SFReply);where    The upper-left corner of the dialog box, in global coordinates.prompt    Ignored.fileFilter    A pointer to an optional file filter function, provided by your application, through which SFGetFile passes files of the specified types.numTypes    The number of file types to be displayed. If you specify a numTypes value of –1, the first filtering passes files of all types.typeList    A list of file types to be displayed.dlgHook    A pointer to your dialog hook function, which handles item hits received from the Dialog Manager. Specify a value of NIL if you want the standard items handled in the standard ways.reply    The reply record, which SFGetFile fills in before returning.DESCRIPTIONSFGetFile displays a dialog box listing the names of a specific group of files from which the user can select one to be opened (as during an Open menu command). During the dialog, SFGetFile gets and handles events (possibly with the assistance of application-defined callback routines) until the user completes the interaction, either by selecting a file to open by canceling the open operation. SFGetFile returns the user’s input in a standard file reply record. SPECIAL CONSIDERATIONSSFGetFile may move memory; your application should not call it at interrupt time.3SFPGetFileCall the SFPGetFile procedure when your application requires more control over the Open dialog box than is possible using SFGetFile.PROCEDURE SFPGetFile (where: Point; prompt: Str255;                                fileFilter: FileFilterProcPtr;                                numTypes: Integer; typeList: SFTypeList;                                dlgHook: DlgHookProcPtr;                                VAR reply: SFReply; dlgID: Integer;                                filterProc: ModalFilterProcPtr);where    The upper-left corner of the dialog box, in global coordinates.prompt    Ignored.fileFilter    A pointer to an optional file filter function, provided by your application, through which SFPGetFile passes files of the specified types.numTypes    The number of file types to be displayed. If you specify a numTypes value of –1, the first filtering passes files of all types.typeList    A list of file types to be displayed.dlgHook    A pointer to your dialog hook function, which handles item hits received from the Dialog Manager. Specify a value of NIL if you have not added any items to the dialog box and want the standard items handled in the standard ways.reply    The reply record, which SFPGetFile fills in before returning.dlgID    The resource ID of a customized dialog template. filterProc    A pointer to your modal-dialog filter function, which determines how the ModalDialog procedure filters events when called by the SFPGetFile procedure. Specify a value of NIL if you are not supplying your own function.DESCRIPTIONSFPGetFile is an alternative to SFGetFile when you want to display a customized Open dialog box or handle the default dialog box in a customized way. During the dialog, SFPGetFile gets and handles events (possibly with the assistance of application-defined callback routines) until the user completes the interaction, either by selecting a file to open by canceling the open. SFPGetFile returns the user’s input in a standard file reply record. SPECIAL CONSIDERATIONSSFPGetFile may move memory; your application should not call it at interrupt time.Summary of the Standard File PackageConstantsCONST    {Gestalt selector and reply}    gestaltStandardFileAttr                                =    'stdf';    gestaltStandardFile58                                =     0;    {standard dialog resource IDs}    sfPutDialogID                                =    -6043;            {Save dialog box}    sfGetDialogID                                =    -6042;            {Open dialog box}    {items that appear in both the Open and Save dialog boxes}    sfItemOpenButton                                =    1;            {Save or Open button}    sfItemCancelButton                                =    2;            {Cancel button}    sfItemBalloonHelp                                =    3;            {Balloon Help}    sfItemVolumeUser                                =    4;            {volume icon and name}    sfItemEjectButton                                =    5;            {Eject button}    sfItemDesktopButton                                =    6;            {Desktop button}    sfItemFileListUser                                =    7;            {display list}    sfItemPopUpMenuUser                                =    8;            {directory pop-up menu}    sfItemDividerLinePict                                =    9;            {dividing line between buttons}    {items that appear in Save dialog boxes only}    sfItemFileNameTextEdit                                =    10;            {filename field}    sfItemPromptStaticText                                =    11;            {filename prompt text area}    sfItemNewFolderUser                                =    12;            {New Folder button}    {pseudo-items available prior to version 7.0}    sfHookFirstCall                                =    -1;            {initialize display}    sfHookCharOffset                                =    $1000;            {offset for character input}    sfHookNullEvent                                =    100;            {null event}    sfHookRebuildList                                =    101;            {redisplay list}    sfHookFolderPopUp                                =    102;            {display parent-directory menu}    sfHookOpenFolder                                =    103;            {display contents of selected }                                                    { folder or volume}    {additional pseudo-items introduced in version 7.0}    sfHookLastCall                                =    -2;            {clean up after display}    sfHookOpenAlias                                =    104;            {resolve alias}    sfHookGoToDesktop                                =    105;            {display contents of desktop}    sfHookGoToAliasTarget                                =    106;            {select target of alias}    sfHookGoToParent                                =    107;            {display contents of parent}    sfHookGoToNextDrive                                =    108;            {display contents of next drive}    sfHookGoToPrevDrive                                =    109;            {display contents of previous drive}    sfHookChangeSelection                                =    110;            {select target of reply record}    sfHookSetActiveOffset                                =    200;            {switch active item}    {refCon field in the window record in the dialog record}    sfMainDialogRefCon                                =    'stdf';            {main dialog box}    sfNewFolderDialogRefCon                                =    'nfdr';            {New Folder dialog box}    sfReplaceDialogRefCon                                 =    'rplc';            {name conflict dialog box}    sfStatWarnDialogRefCon                                =    'stat';            {stationery warning}    sfErrorDialogRefCon                                =    'err ';            {general error report}    sfLockWarnDialogRefCon                                =    'lock';            {software lock warning}    {resource IDs and item numbers of pre-7.0 dialog boxes}    putDlgID                                =    -3999;            {Save dialog box}    putSave                                =    1;            {Save button}    putCancel                                =    2;            {Cancel button}    putEject                                =    5;            {Eject button}    putDrive                                =    6;            {Drive button}    putName                                =    7;            {filename field}    getDlgID                                =    -4000;            {Open dialog box}    getOpen                                =    1;            {Open button}    getCancel                                =    3;            {Cancel button}    getEject                                =    5;            {Eject button}    getDrive                                =    6;            {Drive button}    getNmList                                =    7;            {list of names}    getScroll                                =    8;            {scroll bar}Data TypesStandard File Reply RecordsTYPE    StandardFileReply                        =                {enhanced standard file reply record}    RECORD        sfGood:                    Boolean;                {TRUE if user did not cancel}        sfReplacing:                    Boolean;                {TRUE if replacing file with same name}        sfType:                    OSType;                {file type}        sfFile:                    FSSpec;                {selected file, folder, or volume}        sfScript:                    ScriptCode;                {script of file, folder, or volume name}        sfFlags:                    Integer;                {Finder flags of selected item}        sfIsFolder:                    Boolean;                {selected item is a folder}        sfIsVolume:                    Boolean;                {selected item is a volume}        sfReserved1:                    LongInt;                {reserved}        sfReserved2:                    Integer;                {reserved}    END;    SFReply                        =                {original standard file reply record}    RECORD        good:                    Boolean;                {TRUE if user did not cancel}        copy:                    Boolean;                {reserved}        fType:                    OSType;                {file type}        vRefNum:                    Integer;                {working directory reference number}        version:                    Integer;                {reserved}        fName:                    Str63;                {filename}    END;Standard File Type List    SFTypeList                            =    ARRAY[0..3] OF OSType;Callback Routine Pointer Types    DlgHookProcPtr                            =    ProcPtr;                {dialog hook function}        DlgHookYDProcPtr                            =    ProcPtr;                {dialog hook function with data}        FileFilterProcPtr                            =    ProcPtr;                {file filter function}    FileFilterYDProcPtr                            =    ProcPtr;                {file filter function with data}    ModalFilterProcPtr                            =    ProcPtr;                {modal-dialog filter}    ModalFilterYDProcPtr                            =    ProcPtr;                {modal-dialog filter with data}    ActivateYDProcPtr                            =    ProcPtr;                {activation procedure}RoutinesSaving FilesPROCEDURE StandardPutFile    (prompt: Str255; defaultName: Str255; VAR reply: StandardFileReply);PROCEDURE CustomPutFile    (prompt: Str255; defaultName: Str255; VAR reply: StandardFileReply; dlgID: Integer; where: Point; dlgHook: DlgHookYDProcPtr; filterProc: ModalFilterYDProcPtr; activeList: Ptr; activateProc: ActivateYDProcPtr; yourDataPtr: UNIV Ptr);PROCEDURE SFPutFile    (where: Point; prompt: Str255; origName: Str255; dlgHook: DlgHookProcPtr; VAR reply: SFReply);PROCEDURE SFPPutFile    (where: Point; prompt: Str255; origName: Str255; dlgHook: DlgHookProcPtr; VAR reply: SFReply; dlgID: Integer; filterProc: ModalFilterProcPtr);Opening FilesPROCEDURE StandardGetFile    (fileFilter: FileFilterProcPtr; numTypes: Integer; typeList: SFTypeList; VAR reply: StandardFileReply);PROCEDURE CustomGetFile    (fileFilter: FileFilterYDProcPtr; numTypes: Integer; typeList: SFTypeList; VAR reply: StandardFileReply; dlgID: Integer; where: Point; dlgHook: DlgHookYDProcPtr; filterProc: ModalFilterYDProcPtr; activeList: Ptr; activateProc: ActivateYDProcPtr; yourDataPtr: UNIV Ptr);PROCEDURE SFGetFile    (where: Point; prompt: Str255; fileFilter: FileFilterProcPtr; numTypes: Integer; typeList: SFTypeList; dlgHook: DlgHookProcPtr; VAR reply: SFReply);PROCEDURE SFPGetFile    (where: Point; prompt: Str255;fileFilter: FileFilterProcPtr;numTypes: Integer; typeList: SFTypeList;dlgHook: DlgHookProcPtr; VAR reply: SFReply; dlgID: Integer; filterProc: ModalFilterProcPtr);Application-Defined RoutinesFUNCTION MyStandardFileFilter    (pb: CInfoPBPtr): Boolean;FUNCTION MyCustomFileFilter    (pb: CInfoPBPtr; myDataPtr: Ptr): Boolean;FUNCTION MyDlgHook    (item: Integer; theDialog: DialogPtr; myDataPtr: Ptr): Integer;FUNCTION MyModalFilter    (theDialog: DialogPtr; VAR theEvent: EventRecord; VAR itemHit: Integer): Boolean;FUNCTION MyModalFilterYD    (theDialog: DialogPtr; VAR theEvent: EventRecord; VAR itemHit: Integer; myDataPtr: Ptr): Boolean;PROCEDURE MyActivateProc    (theDialog: DialogPtr; itemNo: Integer; activating: Boolean; myDataPtr: Ptr);Assembly-Language InformationNew Standard File Reply RecordsfGood    byte    command-valid flagsfReplacing    byte    replace existing file flagsfType    4 bytes    file typesfFile    70 bytes    selected itemsfScript    2 bytes    display scriptsfFlags    2 bytes    Finder flags from catalogsfIsFolder    byte    folder flagsfIsVolume    byte    volume flagsfReserved1    4 bytes    reservedsfReserved2    2 bytes    reservedOld Standard File Reply Recordgood    byte    command-valid flagcopy    byte    reservedfType    4 bytes    file typevRefNum    2 bytes    working directory reference numberversion    2 bytes    reservedfName    64 bytes    name of file (length byte followed by up to 63 characters)Trap Macro Requiring Routine Selector_Pack3Selector    Routine$0001    SFPutFile$0002    SFGetFile$0003    SFPPutFile$0004    SFPGetFile$0005    StandardPutFile$0006    StandardGetFile$0007    CustomPutFile$0008    CustomGetFileIndexSymbols'DITL' resource typefor custom Open and Save dialog boxes16 to 17'DLOG' resource type16Numerals2435Aactivation procedures29BBalloon Helpwhen using enhanced Standard File Package routines18when using original Standard File Package routines18Balloon Help on-line assistance.See also help balloons18dialog boxes for saving and opening files18Ccallback routineswith Standard File Package routines15, 18 to 29compatibilitycustomized standard file dialog boxes31copy field35current directoryin Standard File Package dialog boxes5, 30 to 31current diskin Standard File Package dialog boxes5, 30 to 31CustomGetFile procedure41CustomPutFile procedure36Ddialog boxesfor saving and opening files4 to 11customizing14 to 18item numbers21dialog hook functions19 to 25directoryin Standard File Package dialog boxes.See current directorydiskin Standard File Package dialog boxes.See current diskFfile filter functionsfor standard file display list18file formatsin Standard File Package dialog boxes8File menuOpen command11Save As command11Save command11file typesfiltering Standard File display list by40filesuser interface for saving and opening3 to 49Kkeyboard equivalentsin standard file dialog boxes7Mmenu commandsOpen (File menu)11Save (File menu)11Save As (File menu)11modal-dialog filter functionsfor Standard File Package dialogs27 to 29NNew Folder dialog box7, 33OOpen command (File menu)11Ppop-up menusin Standard File Package dialog boxes9pseudo-items22 to 25Rreply recordsfor Standard File Package12, 32 to 35resource types'DITL'7'DLOG'16SSave As command (File menu)11Save command (File menu)11SFGetFile procedure43SFPGetFile procedure44SFPPutFile procedure39SFPutFile procedure38SFReply data type34Standard File Package3 to 49activation procedures29callback routines18 to 29compatibility with earlier procedures31 to 32data structures in32 to 35dialog hook functions19 to 25file filter functions18modal-dialog filter functions27 to 29opening files4 to 5, 39 to 44reply record11 to 12, 32 to 35routines in35 to 44saving files6 to 12, 35 to 39testing for features11user interface guidelines10 to 11StandardFileReply data type12, 32StandardGetFile procedure4, 6, 13, 40StandardPutFile procedure36stationery padshandled by Standard File Package33Uupdate eventsand Standard File Package routines28ZzzfName field35zzfType field35zzgood field35zzrefCon field25zzsfErrorDialogRefCon constant25zzsfFile field12, 33zzsfFlags field34zzsfGood field12, 33zzsfHookChangeSelection constant23zzsfHookCharOffset constant24zzsfHookFirstCall constant23zzsfHookFolderPopUp constant24zzsfHookGoToAliasTarget constant24zzsfHookGoToDesktop constant24zzsfHookGoToNextDrive constant24zzsfHookGoToParent constant24zzsfHookGoToPrevDrive constant25zzsfHookLastCall constant23zzsfHookNullEvent constant23zzsfHookOpenAlias constant24zzsfHookOpenFolder constant24zzsfHookRebuildList constant23zzsfHookSetActiveOffset constant23zzsfIsFolder field34zzsfIsVolume field34zzsfItemBalloonHelp constant20zzsfItemCancelButton constant22zzsfItemDesktopButton constant22zzsfItemDividerLinePict constant20zzsfItemEjectButton constant22zzsfItemFileListUser constant22zzsfItemFileNameTextEdit constant22zzsfItemNewFolderUser constant22zzsfItemOpenButton constant22zzsfItemPopUpMenuUser constant22zzsfItemPromptStaticText constant20zzsfItemVolumeUser constant22zzsfLockWarnDialogRefCon constant25zzsfMainDialogRefCon constant25zzsfNewFolderDialogRefCon constant25zzsfReplaceDialogRefCon constant25zzsfReplacing field12, 33zzsfReserved1 field34zzsfReserved2 field34zzsfScript field34zzsfStatWarnDialogRefCon constant25zzsfType field33zzsmSystemScript constant34zzversion field35zzvRefNum field35The Disk Initialization PackageAbout the Disk Initialization Package4-3Disk Initialization4-4The Disk Initialization User Interface4-5Bad Block Sparing4-7Using the Disk Initialization Package4-9Responding to Disk-Inserted Events4-9Erasing Initialized Disks4-11Overriding the Standard Initialization Interface4-12Changing Default Volume Characteristics4-14Reference to the Disk Initialization Package4-16Routines4-16Loading and Unloading the Disk Initialization Package4-16Initializing a Disk4-18Low-Level Disk Initialization Routines4-20Summary of the Disk Initialization Package4-234The Disk Initialization PackageThis chapter describes the Disk Initialization Package, the part of the Operating System that allows you to initialize disks and erase the contents of previously initialized disks. The Disk Initialization Package provides a routine that allows you to present the standard user interface for initializing and naming disks. It also provides routines that allow you to initialize disks without presenting that standard user interface.You need to read this chapter if your application does not mask out disk-inserted events. When your application receives a disk-inserted event, it must determine whether the inserted disk is valid. If the disk is not valid, your application can use the Disk Initialization Package to present the user with the standard interface for initializing the disk.To use this chapter, you should already be familiar with the Event Manager, which sends your application a disk-inserted event whenever a disk is inserted (unless you have masked out such events). You need to examine the message field of that event to determine whether the inserted disk is already initialized. You also need to be familiar with the File Manager if your application changes the default volume characteristics of newly initialized volumes.This chapter begins by describing the operation of the Disk Initialization Package, includingn    formatting, verifying, and zeroing a diskn    the standard user interface for initializing and naming a diskn    bad block sparingThen this chapter shows how you cann    determine whether an inserted disk is validn    present the standard user interface to initialize and name an invalid diskn    present the standard user interface to erase a diskn    initialize or erase a disk without using the standard user interfacen    change the default volume characteristics of newly initialized volumesAbout the Disk Initialization PackageThe Disk Initialization Package is the part of the Macintosh Operating System that manages the process of initializing disks. This package accepts requests to initialize a disk and translates them into control calls for the corresponding disk driver. The Disk Initialization Package itself does not perform the low-level formatting or verification of the disk; instead, it simply manages the communication between the software requesting that a particular disk be initialized and the appropriate disk driver.In theory, you can use the Disk Initialization Package to initialize any writable disk drive. In practice, however, most SCSI disk drivers ignore formatting control calls. Instead, low-level disk operations such as formatting and verification are usually performed by a utility program supplied with the disk. As a result, this chapter assumes that the disk to be initialized is a 3.5 inch floppy disk or an Apple Hard Disk 20, all of which are accessed through the Disk Driver.<36pt\>\x12 <8bat\>uUsually, the Finder or the Standard File Package calls the Disk Initialization Package when the user inserts an uninitialized disk. Occasionally the user will insert a disk when your application is frontmost. At that time, the Operating System generates a disk-inserted event. If your application has not masked out such events, it receives an event record for that event when it makes an event call and no events with higher priority are pending. You then need to determine whether the inserted disk is valid (as indicated by a value in the event record). If the disk is not valid, you should call the Disk Initialization Package to allow the user to initialize the disk or, if desired, eject it.If your application masks out disk-inserted events, the event stays in the event queue until your application calls the Standard File Package (which automatically processes disk-inserted events) or until the current application can handle disk-inserted events. In general, it’s best not to mask out disk-inserted events and to handle them as described later in this chapter; otherwise, the user is likely to become confused when, after inserting an uninitialized or damaged disk, no disk icon appears on the desktop and no standard disk initialization dialog box appears. (Icons of initialized and undamaged disks always appear on the desktop, even if the current application ignores disk-inserted events.)Disk InitializationDisk initialization is the process of making a disk usable by the Macintosh Operating System. When shipped, most floppy disks are uninitialized because different operating systems have different initialization requirements. On Macintosh computers, disk initialization consists of three independent steps:n    disk formattingn    disk verificationn    disk zeroingAll three steps must be performed successfully before the disk is considered initialized (or valid). You can use a single Disk Initialization Package routine, DIBadMount, to perform all three operations in sequence, or you can perform any one of them by calling a corresponding low-level routine (either DIFormat, DIVerify, or DIZero). In general, your application should use the standard user interface described in the following section to initialize a disk.The first step in the initialization process is disk formatting. Formatting a disk consists of writing special information onto a disk so that the disk driver can read from and write to the disk. This involves dividing the total usable space into sectors and tracks. See the Disk Driver chapter in the Devices volume for a description of how a disk is divided into tracks and sectors.The second step in the disk-initialization process is disk verification. Verifying a disk consists of reading every bit on the disk to ensure that the disk has been formatted correctly and  contains no bad blocks. If an error occurs during the reading of any single bit, the verification is considered unsuccessful.The third and final step in the disk-initialization process is disk zeroing. Zeroing a disk consists of creating on the disk the data structures and files necessary for the disk to be recognized as a hierarchical file system (HFS) volume. In particular, zeroing a disk places a master directory block (MDB), a volume bitmap, and a catalog file in appropriate locations on the disk. (For information on the locations and sizes of these items, see the description of the organization of data in a volume in the chapter “The File Manager” in this volume.) The volume bitmap and catalog file are set up to represent a volume containing no user files. As a result, zeroing a disk makes any files previously located on the disk inaccessible.Beginning in system software version 7.0, zeroing a disk also causes the Disk Initialization Package to attempt to remove any bad blocks (as identified during the disk-verification process) from the pool of available blocks on the disk. See “Bad Block Sparing” for a description of this capability.The Disk Initialization User InterfaceThe Finder and the Standard File Package both handle disk-inserted events for uninitialized disks by presenting a disk initialization dialog box asking the user whether the disk should be ejected or initialized. Your application too can easily call a Disk Initialization Package routine that generates such a dialog box when the user inserts an invalid disk. Figure 4-1 illustrates one configuration of the dialog box.The unreadable disk dialogThe appearance of the disk initialization dialog box changes to reflect changing conditions. For example, the icon changes to show which drive contains the disk. Also, the text of the dialog box changes according to what is wrong with the disk. The text might read “This is not a Macintosh disk” if the Disk Initialization Package detects that the disk has been formatted for use on another operating system. Or, it might notify the user that a high-density disk can be used only on an Apple SuperDrive. Finally, if a user inserts a single-sided disk into any disk drive, or a high-density disk into a high-density disk drive, then the Disk Initialization Package changes the buttons in the dialog box, as illustrated in Figure 4-2, because such disks can be formatted in only one way.Alternate buttons for the disk initialization dialogRegardless of the initial appearance of the disk initialization dialog box, it disappears if the user clicks Eject or Cancel. If, however, the user decides to initialize the disk, the text in the dialog box changes to warn the user that initialization erases any previous data on the disk, as illustrated in Figure 4-3.Disk initialization warningFinally, if the user decides to initialize the disk, the contents of the dialog box change so that the user can name the new disk, as illustrated in Figure 4-4.Naming a new diskAfter the user names the disk, the Disk Initialization Package attempts to initialize it. If an error occurs and the initialization fails, an alert box notifies the user, and the disk is ejected.The Disk Initialization Package also provides a mechanism for using the standard interface to reinitialize disks that are already formatted. (This mechanism is useful, for example, to allow the user to reinitialize single-sided disks as double-sided disks.) The Finder takes advantage of this mechanism with its Erase Disk command, illustrated in Figure 4-5. After the user selects the erase operation from this dialog box, the reinitialization begins immediately, without further warnings. If desired, your application can use this same standard interface to allow users to reinitialize mounted disks (other than the startup volume). Your application can customize the text to be displayed in such a dialog box. Note that only a few utility applications actually need to provide users with this capability.Erasing a disk in the FinderIf you are writing a utility program such as a disk-copying application, you might wish to initialize new disks or reinitialize valid disks without displaying the standard disk initialization dialog box. For example, your application might allow users to initialize multiple disks without having to respond to the standard dialog box each time. The Disk Initialization Package provides low-level routines that allow you to do so. Unless you are writing a utility program of this type, you don’t need to use these routines.Bad Block SparingBeginning with system software version 7.0, the Disk Initialization Package tries to initialize a disk even if it contains some bad blocks; this feature is called bad block sparing. Without bad block sparing, the Disk Initialization Package considers a disk unusable even if just one block  is bad. With bad block sparing, however, the Disk Initialization Package attempts to work around the bad block by removing it from the pool of available free blocks. This prevents the File Manager from allocating the block to a file. Except in cases (described later) involving critical blocks on a disk, the Disk Initialization Package can usually initialize a disk that would previously have been rejected as invalid. This section describes the operation of bad block sparing.Applications that manipulate disks using File Manager routines are unaffected by bad block sparing. Software that accesses blocks directly from the disk or that makes assumptions about the physical blocks on a disk (such as a disk scavenger, recovery, or backup utility) is likely to fail or cause a loss of data on disks containing spared blocks.<36pt\>\x12 <8bat\>sThe bad block sparing occurs during the disk-zeroing phase of disk initialization. As a result, sparing occurs only when you call DIZero or DIBadMount (which internally calls DIZero), never when you call DIFormat or DIVerify. The only visible sign of the sparing process is an additional dialog box that contains the message “Re-Verifying Disk”.Disks without bad blocks are initialized exactly as in previous versions of system software. The sparing algorithm is invoked only if the disk verification fails during a call to the DIBadMount function or if the DIZero function encounters bad blocks during its zeroing. The sparing algorithm proceeds by making a second pass over the disk, writing and then reading back a test pattern. This testing is done a single track at a time. If any retries or errors occur during this test, all the sectors in the track are deemed bad.If more than 25 percent of the disk is found to contain bad blocks, if the I/O errors appear to be due to hardware failure rather than media failure, or if certain critical sectors (described later) are bad, then the initialization fails just as it would have without the bad block sparing. Otherwise, the HFS volume structure is written to the disk. After the volume structure has been written, the Disk Initialization Package performs several further operations during bad block sparing.    1.    It sets the appropriate bits in the volume bitmap to indicate that the bad blocks are allocated to a file.    2.    It creates file extent descriptors for the bad blocks and inserts then into the volume extents B*-tree so that the free-space scavenging that occurs at volume mount time (or that is done by disk utilities such as Disk First Aid) does not reintroduce the bad blocks into the volume bitmap. A special file ID (5) is used for these extents.    3.    It sets bit 9 in the drAtrb field of the master directory block to indicate that bad blocks in the disk have been spared.    4.    On 800K floppy disks only, it reduces the number of allocation blocks on the disk  by 1 (from 1594 to 1593), to prevent previous versions of the Finder from doing disk-to-disk copies physically (that is, sector by sector). This copying operation would fail during an attempt to copy the bad blocks. The Finder does physical copies as an optimization only on disks containing exactly 1594 allocation blocks.The critical sectors (those that must be good even on a spared disk) include the boot blocks, the master directory block and the spare master directory block, the volume bitmap, and the initial extents for the catalog and extents B*-tree files of the volume.Notice that the bad block sparing algorithm does not create any new entries in the volume’s catalog file. In other words, steps (1) and (2) of the algorithm trick the File Manager into thinking that the bad blocks have been allocated to some file, although no file is actually created to contain those blocks. For this reason, directory enumerations and file-by-file copies can proceed as they would have without bad block sparing. (If a file were created for the bad blocks, that file would need a parent directory; in that case, reading the catalog file to determine how many files that directory contains would produce erroneous results.)The bad block sparing capability described in this section applies only during disk initialization. The Operating System cannot correct problems that occur after a disk has been initialized (except by reinitializing the disk).<36pt\>\x12 <8bat\>uUsing the Disk Initialization PackageThe Disk Initialization Package provides standard interfaces that allow your applicationn    to respond to the user’s insertion of an unformatted or damaged disk by presenting the standard disk initialization dialog boxn    to reinitialize valid disks, preserving their names but destroying their contentsYou can override these standard interfaces by calling low-level Disk Initialization Package routines, and you can also override the default volume characteristics that the Disk Initialization Package gives to hierarchical volumes.Responding to Disk-Inserted EventsWhen the user inserts a disk, the Operating System attempts to mount the volume on the disk by calling the File Manager function MountVol. If the volume is successfully mounted, an icon representing the disk appears on the desktop. The Operating System then generates a disk-inserted event. If the user is interacting with a standard file dialog box, the Standard File Package intercepts the disk-inserted event and handles it. Otherwise, the event is left in the event queue for you applciaiton to retrieve.Your application must either mask out disk-inserted events or process them by checking to see whether the inserted disk is invalid. If you mask out such events, then each disk-inserted event needlessly occupies a position in the event queue until the user brings an application that can handle such events to the foreground or until your application invokes the Standard File Package. Also, displaying the disk initialization dialog box long after the disk has been inserted is likely to confuse the user. However, you might wish to mask out disk-inserted events when you create modal dialogs in which you process events with WaitNextEvent rather than ModalDialog. That way, your application can process disk-inserted events as soon as the modal dialog box closes.By default, the Dialog Manager’s ModalDialog procedure automatically masks out disk-inserted events so that your application can handle them when dialog boxes close. If you wish to accept disk-inserted events in a modal dialog box in which you call ModalDialog, you must supply a filter procedure for the dialog box. See the chapter “The Dialog Manager” in the Toolbox volume for information on how to write a filter procedure.<36pt\>\x12 <8bat\>uBecause handling disk-inserted events is easy, there is no good reason for your application to mask out the events in its main event loop. Listing 4-1 defines a procedure that your application can call when it receives a disk-inserted event.Responding to disk-inserted eventsPROCEDURE DoDiskEvent (myEvent: EventRecord);VAR    myPoint:                Point;    myErr:                OSErr;BEGIN    IF HiWord(myEvent.message) <> noErr THEN        BEGIN                                            {attempt to mount was unsuccessful}            DILoad;                                        {load Disk Initialization Package}            SetPt(myPoint, 120, 120);                                        {set top left of dialog box}            myErr := DIBadMount(myPoint, myEvent.message);                                                    {notify the user}            DIUnload;                                        {unload Disk Initialization Package}        END    ELSE                                                {attempt to mount was successful}        ;                                            {do other processing}END;The DoDiskEvent procedure in Listing 4-1 checks the high word of the event message to see if the disk is mounted properly. If it has not been mounted, DoDiskEvent calls the Disk Initialization Package’s DIBadMount function, which displays the disk initialization dialog box. Before doing so, DoDiskEvent calls DILoad to ensure that the Disk Initialization Package and its dialog box are loaded into memory. If you did not call DILoad and the user started up with a floppy system startup disk, the Operating System might require that the user reinsert the system disk and might then attempt to initialize that disk. In Listing 4-1, if the user did start up with a floppy system startup disk on a single floppy-drive system, the DILoad procedure requests that the user insert the system disk so that it can read the necessary resources, and then it ejects that disk so that the user can again put the disk to be initialized into the drive. After calling DIBadMount to handle the uninitialized disk, DoDiskEvent calls DIUnload to release the resources DILoad read into memory.Beginning with system software version 7.0, the first parameter to DIBadMount is ignored, and the disk initialization dialog box is automatically centered on the screen. The procedure in Listing 4-1 ignores the result code returned by DIBadMount because ordinarily it does not concern your application. If an error does occur during initialization, DIBadMount informs the user and ejects the disk.Erasing Initialized DisksYou can also use the standard interface provided by the DIBadMount procedure to reinitialize disks that are already initialized correctly. Doing so permanently erases their contents, but does not change their names.To reinitialize a disk, call DIBadMount with the high word of the event message equal to the result code noErr. DIBadMount presents the standard interface to initialize the disk in the drive whose number is specified by the low word of the event message. However, because the Disk Initialization Package cannot know why your application wishes to reinitialize a disk, it cannot provide the initial text for the disk initialization dialog box. Therefore, your application must use the Dialog Manager’s ParamText procedure to create a customized message, as illustrated in Listing 4-2.If you need to reinitialize a valid disk but do not have access to the event message from when the disk was formatted, you can artificially create an event message by setting the low-order bits of the event message to an integer representing the drive number, as follows:myEvtMessage := ORD4(driveNum);Doing so sets each of the high-order bits of the artificial event message to 0, which is desired because the constant noErr is equal to 0.Listing 4-2 defines a procedure for displaying a disk initialization dialog box that allows the user to reinitialize the disk in the drive specified by driveNum. The disk initialization dialog box displays the text specified in the myString parameter. The procedure in Listing 4-2 in turn calls a procedure named DoError. You must define DoError to process the result code if the initialization did not complete successfully. The disk initialization dialog box does alert the user if the operation does not complete successfully, and does eject the disk. However, your application might need to know when a disk that was formerly mounted correctly is no longer mounted because reinitialization failed.Reinitializing a valid diskPROCEDURE DoEraseDisk (driveNum: Integer; myString: Str255);VAR    eventMessage:                        LongInt;                        {artificially created message}    myPoint:                        Point;                            myErr:                         Integer;                        {result code}BEGIN    DILoad;                                                {load Disk Initialization Package}    ParamText(myString, '', '', '');                                                {set dialog text}    eventMessage := ORD4(driveNum);                                                {create event message}    SetPt(myPoint, 120, 120);                                                {set top left of dialog box}    myErr := DIBadMount(myPoint, eventMessage);                                                    {allow user to confirm erase}    IF myErr <> noErr THEN        DoError(myErr);                                            {respond to error, if necessary}    DIUnload;                                                {unload Disk Initialization Package}END;Overriding the Standard Initialization InterfaceThe disk initialization dialog box provides an easy-to-use, standard interface for initializing and reinitializing disks. However, if you wish, you can use three low-level Disk Initialization Package functions that accomplish the three stages of disk initialization without the standard interface. The three functions are DIFormat, DIVerify, and DIZero. The DIFormat function attempts to format the disk, the DIVerify function verifies whether the format was successful, and the DIZero function updates the newly initialized volume’s characteristics and attempts to spare any bad blocks on the disk.Listing 4-3 shows how to reinitialize a disk without using the standard interface. The low-level functions work only if the disk is not already mounted in the disk drive. Therefore, Listing 4-3 uses high-level File Manager calls to unmount the volume and to remember the volume’s name, so that it can be restored later. Because you are no longer using the standard interface, you must define the DoError procedure so that you can alert the user about an error.Reinitializing a validly formatted disk without using the standard interfacePROCEDURE DoEraseDisk (driveNum: Integer);VAR    myErr:                    OSErr;                                    {result code}    volName:                    Str255;                                    {name of volume}    oldVRefNum:                    Integer;                                    {to unmount volume}    oldFreeBytes:                     LongInt;                                    {for GetVInfo call}BEGIN    DILoad;                                                        {load Disk Init. Package}    myErr := GetVInfo(driveNum, @volName, oldVRefNum, oldFreeBytes);                                                            {remember name of volume}    IF myErr = noErr THEN        myErr := UnmountVol(@volName, oldVRefNum);                                                            {unmount the disk}    IF myErr = noErr THEN            myErr := DIFormat(driveNum);                                                    {format the disk}    IF myErr = noErr THEN                                    myErr := DIVerify(driveNum);                                                    {verify format}    IF myErr = noErr THEN        myErr := DIZero(driveNum, volName);                                                    {update volume information}    IF myErr <> noErr THEN        DoError(myErr);                                                    {respond to error}    DIUnload;                                                        {unload Disk Init. Package}END;If you wish, you can also respond to a user’s insertion of an uninitialized or damaged disk by simply formatting the disk without using the standard interface. Listing 4-4 defines a procedure for this purpose. Listing 4-4 differs from Listing 4-3 only in that it does not begin by unmounting the volume (because the File Manager does not mount uninitialized or damaged disks).Initializing an uninitialized disk without using the standard interfacePROCEDURE DoInitDisk (driveNum: Integer; volName: Str255);VAR    myErr:                    OSErr;                                    {result code}BEGIN    DILoad;                                                        {load Disk Init. Package}    myErr := DIFormat(driveNum);                                                        {format the disk}    IF myErr = noErr THEN                                    myErr := DIVerify(driveNum);                                                    {verify format}    IF myErr = noErr THEN        myErr := DIZero(driveNum, volName);                                                    {update volume information}    IF myErr <> noErr THEN        DoError(myErr);                                                    {respond to error}    DIUnload;                                                        {unload Disk Init. Package}END;Changing Default Volume CharacteristicsThe Disk Initialization Package must set certain volume characteristics when it creates an HFS directory on a volume. Default values for these characteristics are stored in an HFS defaults record in ROM. If you wish, you can override those default values by placing a pointer to an HFS defaults record in the low-memory global variable FmtDefaults. The Disk Initialization Package uses the record stored in ROM whenever this low-memory global variable contains NIL.Most applications do not need to alter the default volume characteristics. This technique is useful primarily for applications such as backup utilities, that intelligently adjust the allocation block size and clump size to maximize the amount of data written to a backup volume.<36pt\>\x12 <8bat\>uThe HFSDefaults data structure defines the HFS defaults record.TYPE HFSDefaults =RECORD    sigWord:                Packed Array[0..1] OF Byte;                                        {signature word}    abSize:                LongInt;                                        {allocation block size in bytes}    clpSize:                LongInt;                                        {clump size in bytes}    nxFreeFN:                LongInt;                                        {next free file number}    btClpSize:                LongInt;                                        {B*-tree clump size in bytes}    rsrv1:                Integer;                                        {reserved}    rsrv2:                Integer;                                        {reserved}    rsrv3:                Integer;                                        {reserved}END;sigWord    The signature word to be used for newly initialized volumes. By default, this field is set to 'BD' (hexadecimal $4244). You must set this field to 'BD' for the volume to be recognized as an HFS volume.abSize    The number of bytes in each allocation block on newly initialized volumes. If you set this field to 0, the number of bytes in each allocation block is computed according to the following formula:                                abSize = (1 + (volSize in blocks/64K)) * 512 bytes    By default, this field is set to 0.clpSize    The number of bytes to be used for the clump on newly initialized volumes. By default, this field is set to 4*abSize.nxFreeFN    The next free file number on newly initialized volumes. By default, this field is set to 16.btClpSize    The number of bytes to be used for the B*-tree clump on newly initialized volumes. If you set this field to 0, the number of bytes to be used for the B*-tree clump is computed according to the following formula:                                btClpSize = ((volSize in blocks)/128) * 512 bytes    By default, this field is set to 0.rsrv1    Reserved.rsrv2    Reserved.rsrv3    Reserved.The code in Listing 4-5 defines such a record, stores it in the system heap (so that the record remains in memory after the application terminates), and makes the low-memory global variable FmtDefaults a pointer to that record. Note that changing the default volume characteristics does not affect volumes that you have already initialized, but only volumes to be initialized.Changing default volume characteristicsPROCEDURE ChangeHFSDefaults;CONST    FmtDefaults = $039E;                                                    {address of low-memory global}TYPE    HFSDefaultsPtr = ^HFSDefaults;                                                    {pointer to override record}    HFSDefaultsHandle = ^HFSDefaultsPtr;                                                    {address of above pointer}        VAR    myDefaults:                    HFSDefaultsPtr;BEGIN    myDefaults := HFSDefaultsPtr(NewPtrSysClear(SizeOf(HFSDefaults)));                                                        {allocate record in system heap}    WITH myDefaults^ DO        BEGIN            ...                                            {set fields of record}        END;    HFSDefaultsHandle(FmtDefaults)^ := myDefaults;                                                        {change value of global}END;If you later want to restore the default settings, you can reset the low-memory global variable FmtDefaults to NIL.Reference to the Disk Initialization PackageThis section describes the routines that are specific to the Disk Initialization Package. See “Changing Default Volume Characteristics” for a description of the Pascal data structure for the HFS defaults record.RoutinesThe Disk Initialization Package provides two routines that allow you to load and unload the package, one routine that allows you both to format uninitialized disks that the user inserts and to reinitialize volumes by erasing their data without changing their names, and three low-level routines that allow you to perform the steps of formatting, verifying, and zeroing the disk separately.Loading and Unloading the Disk Initialization PackageEven a user with a hard disk drive might occasionally use a floppy disk to start up the computer. When you call the Disk Initialization Package to initialize a disk, it might need to read a resource from the System resource file. If the disk containing the System resource file is not already mounted, the user might need to switch disks, and system software might accidentally try to reinitialize the startup volume. The DILoad procedure allows you to avoid this problem by ensuring that the resources the Disk Initialization Package needs are preloaded into memory. The DIUnload procedure reverses the effects of DILoad.4DILoadYou can use the DILoad procedure to ensure that the Disk Initialization Package and its associated dialog box and dialog items are in memory.PROCEDURE DILoad;DESCRIPTIONThe DILoad procedure reads the Disk Initialization Package and its associated dialog box and dialog items into memory and makes them unpurgeable. Depending on which Macintosh model the user is using, the Disk Initialization Package and the dialog box and dialog items are either in ROM or in the System file.Ordinarily, you call the DILoad procedure when you anticipate that the user will need to format a disk. The Standard File Package automatically calls DILoad when you call StandardGetFile or StandardPutFile. If you are writing a utility program that frequently needs to initialize disks, such as a disk-copying program, you might call DILoad at the beginning of your application.When you use the low-level disk-initialization routines DIFormat, DIVerify, and DIZero, the Disk Initialization Package does not need to load a dialog box. Therefore, if you use only these routines, you can (if you wish) call the Resource Manager to read just the package resource into memory and the Memory Manager procedure to make it unpurgeable. To read just the package resource into memory, you can call the GetResource function with a resource ID of 2. Then, you need to use the HNoPurge procedure to make the package resource unpurgeable.SPECIAL CONSIDERATIONSBecause the DILoad procedure allocates memory, you should not call it at interrupt time.4DIUnloadTo free the memory space occupied by the Disk Initialization Package, you can call the DIUnload procedure.PROCEDURE DIUnload;DESCRIPTIONDIUnload makes the Disk Initialization Package and its associated dialog box and dialog items purgeable. They remain in memory until the Memory Manager purges the heap zone.If you are using the low-level disk initialization routines and read just the package resource into memory, you can free the memory the package occupies by calling the ReleaseResource procedure.To force the Memory Manager to purge the heap zone so that it really frees the memory occupied by the Disk Initialization Package and its dialog box and dialog items, you can call one of the Memory Manager PurgeMem or MaxMem routines.  For more information, see the chapter “Introduction to the Memory Manager” in this volume.SPECIAL CONSIDERATIONSBecause DIUnload might affect memory, you should not call it at interrupt time.Initializing a DiskYou can use the Disk Initialization Package to initialize uninitialized disks and to reinitialize previously initialized disks. The DIBadMount function accomplishes both tasks.4DIBadMountTo respond to the user’s insertion of an uninitialized or damaged disk, you can call the DIBadMount function.FUNCTION DIBadMount (where: Point; evtMessage: LongInt): Integer;where    The desired location, in global coordinates, of the top-left corner of the disk initialization dialog box. In system software versions 7.0 and later, this parameter is ignored, and the dialog box is automatically centered on the screen.evtMessage    The event message received when the disk is inserted. The high word of this message contains the result code associated with the disk insertion. The low word of this message indicates the number of the drive into which the user inserted the disk.DESCRIPTIONThe DIBadMount function evaluates the result code in evtMessage and responds appropriately. If the result code is noErr, the function allows the user to erase the contents of the disk. If the result code is ioErr, badMDBErr, or noMacDskErr, initializing the disk might correct the problem, and so DIBadMount displays a dialog box that explains the problem and allows the user to initialize the disk. If the result code is extFSErr, memFullErr, nsDrvErr, paramErr, or volOnLinErr, then initializing the disk would not correct the problem. In this case, DIBadMount ejects the disk from the drive and returns the result code.Before presenting the disk initialization dialog box, DIBadMount checks whether the drive contains an already mounted volume. If so, it ejects the disk and returns 2 as its result. This happens rarely and could reflect an error in your application (for example, you forgot to call DILoad, and the user had to switch to the disk containing the System resource file).The DIBadMount function uses just one disk initialization dialog box to cover all disk initialization situations. The dialog box contains many dialog items, which are hidden and shown as appropriate. The dialog box always contains an icon indicating the drive containing the disk to be initialized.The initial text of the disk initialization dialog box depends on the result code received. For example, if you pass noMacDskErr to DIBadMount in the evtMessage parameter, the function alerts the user with the text “This is not a Macintosh disk.” If you pass the result code noErr, your application can customize the message by using the Dialog Manager’s ParamText procedure.The disk initialization dialog box contains a button allowing the user to cancel the initialization and one or two buttons allowing the user to request initialization of the disk. Usually, the cancel button is labeled Eject, but if the result code passed to DIBadMount within the evtMessage parameter is noErr, then the cancel button is labeled Cancel. If the user responds to the disk initialization dialog box by clicking the Eject button, DIBadMount ejects the disk and returns 1 as its result. If the user clicks the Cancel button, DIBadMount returns 1 but does not eject the disk.In most cases, the Initialize button is the only alternative to the Eject or Cancel button. However, if the user inserts a double-sided (but not high-density) disk into a double-sided or high-density disk drive, DIBadMount presents buttons labeled One-Sided and Two-Sided so that the user can choose whether to make the disk single-sided or double-sided. If the user clicks the Initialize button, the One-Sided button, or the Two-Sided button, DIBadMount warns the user that the initialization process erases any existing data on the disks. If the user proceeds, DIBadMount allows the user to name the disk if it is not already named, and then updates the text of the dialog box to inform the user of the progress of the operation. If the operation fails, DIBadMount alerts the user and ejects the disk, returning an appropriate result code.You can use DIBadMount to format hard disks as well as floppy disks. However, you should not attempt to format the startup volume.SPECIAL CONSIDERATIONSBecause the DIBadMount function might allocate memory, you should not call it at interrupt time.RESULT CODES[no name]    2    Disk in specified drive is already mounted[no name]    1    User aborted initializingnoErr    0    No errorparamErr    –50    Drive number specified is badvolOnLinErr    –55    Volume is already on linensDrvErr    –56    No such driveextFSErr    –58    Disk has external file systemlastDskErr    –64    Last of the range of low-level disk errors...firstDskErr    –84    First of the range of low-level disk errorsmemFullErr    –108    Not enough memoryLow-Level Disk Initialization RoutinesIf you do not want to use the standard interface for initializing uninitialized volumes, you can use the Disk Initialization Package’s low-level routines. For example, if you are writing a disk-copying application, initializing a disk might be only part of the copying process. In this case, you might wish to create your own dialog boxes warning the user about the repercussions of initializing a disk and giving information on the progress of the initialization.The three low-level disk-initialization routines are DIFormat, DIVerify, and DIZero. Ordinarily, you call them in that order to format an uninitialized disk, to verify the format, and to set the volume’s volume information block and desktop database.4DIFormatTo format a disk, you can use the DIFormat function.FUNCTION DIFormat (drvNum: Integer): OSErr;drvNum    The number of the drive containing the disk to be formatted.DESCRIPTIONThe DIFormat function attempts to format the disk in the drive specified by the given drive number and returns a result code indicating whether it completed the formatting successfully or failed. Formatting a disk consists of writing special information onto it so that the disk driver can read from and write to the disk.You can use DIFormat to format any unlocked disk, including single-sided disks, double-sided disks, high-density disks, and hard disk drives. It formats both sides of a double-sided disk.You have to unmount a disk before calling the DIFormat function.SPECIAL CONSIDERATIONSYou should not call DIFormat at interrupt time.RESULT CODESnoErr    0    No errorvolOnLinErr    –55    Volume is on-linelastDskErr    –64    Last of the range of low-level disk errors...    firstDskErr    –84    First of the range of low-level disk errors4DIVerifyTo verify a disk you have formatted, you can use the DIVerify function.FUNCTION DIVerify (drvNum: Integer): OSErr;drvNum    The number of the drive containing the disk to be verified.DESCRIPTIONThe DIVerify function verifies the format of the disk in the drive specified by the given drive number. It reads each bit from the disk and returns a result code indicating whether all bits were read successfully or not. The DIVerify function does not affect the contents of the disk itself.SPECIAL CONSIDERATIONSYou should not call DIVerify at interrupt time.RESULT CODESnoErr    0    No errorlastDskErr    –64    Last of the range of low-level disk errors...    firstDskErr    –84    First of the range of low-level disk errors4DIZeroTo complete the disk-initialization process, you can use the DIZero function.FUNCTION DIZero (drvNum: Integer; volName: Str255): OSErr;drvNum    The number of the drive containing the disk to be zeroed.volName    The name of the volume (to be included in the volume information).DESCRIPTIONOn the unmounted volume in the drive specified by the given drive number, the DIZero function sets the volume information, volume bitmap, a file directory, and the desktop database to the settings corresponding to a volume with no files. This function completes the process of making any files previously on the volume permanently inaccessible. If the operation fails, DIZero returns a result code indicating that a low-level disk error occurred. Otherwise, it mounts the volume by calling the File Manager function MountVol and returns that function’s result code.SPECIAL CONSIDERATIONSYou should not call DIZero at interrupt time. In system software version 7.0 and later, DIZero automatically performs bad block sparing, as described earlier in “Bad Block Sparing.”RESULT CODESnoErr    0    No errorioErr    –36    I/O errorparamErr    –50    Drive number specified is badvolOnLinErr    –55    Volume is already on linensDrvErr    –56    No such drivenoMacDskErr    –57    Disk is not a Macintosh diskextFSErr    –58    Disk has external file systembadMDBErr    –60    Master directory block is badlastDskErr    –64    Last of the range of low-level disk errors...firstDskErr    –84    First of the range of low-level disk errorsmemFullErr    –108    Not enough memorySummary of the Disk Initialization PackageData TypesHFS Defaults RecordTYPE HFSDefaults =RECORD    sigWord:                Packed Array[0..1] OF Byte;                                    {signature word}    abSize:                LongInt;                                    {allocation block size in bytes}    clpSize:                LongInt;                                    {clump size in bytes}    nxFreeFN:                LongInt;                                    {next free file number}    btClpSize:                LongInt;                                    {B*-tree clump size in bytes}    rsrv1:                Integer;                                    {reserved}    rsrv2:                Integer;                                    {reserved}    rsrv3:                Integer;                                    {reserved}END;RoutinesLoading and Unloading the Disk Initialization PackagePROCEDURE DILoad;PROCEDURE DIUnload;Initializing a DiskFUNCTION DIBadMount    (where: Point; evtMessage: LongInt): Integer;Low-Level Disk-Initialization RoutinesFUNCTION DIFormat    (drvNum: Integer): OSErr;FUNCTION DIVerify    (drvNum: Integer): OSErr;FUNCTION DIZero    (drvNum: Integer; volName: Str255): OSErr;Global VariablesFmtDefaults    Pointer to substitute values for hierarchical volume directoriesResult Codes[no name]    2    Disk in specified drive is already mounted[no name]    1    User aborted initializingnoErr    0    No errorioErr    –36    I/O errorparamErr    –50    Drive number specified is badvolOnLinErr    –55    Volume is already on linensDrvErr    –56    No such drivenoMacDskErr    –57    Disk is not a Macintosh diskextFSErr    –58    Disk has external file systembadMDBErr    –60    Master directory block is badlastDskErr    –64    Last of the range of low-level disk errorsfirstDskErr    –84    First of the range of low-level disk errorsmemFullErr    –108    Not enough memoryAssembly-Language InformationHFSDefaults Data StructuresigWord    2 bytes    signature wordabSize    4 bytes    allocation block size in bytesclpSize    4 bytes    clump size in bytesnxFreeFN    4 bytes    next free file numberbtClpSize    4 bytes    B*–tree clump size in bytesrsrv1    word    reservedrsrv2    word    reservedrsrv3    word    reservedTrap Macros Requiring Routine Selectors_Pack2Selector    Routine$0000    DIBadMount$0002    DILoad$0004    DIUnload$0006    DIFormat$0008    DIVerify$000A    DIZeroIndexAallocation blocksdefault size of15BB*-tree clumpsdefault size of15bad block sparing7Cclumpsdefault size of15DDIBadMount function18 to ??, 18, ?? to 20DIBadMount function11DIFormat function20 to ??, 20, ?? to 21DILoad procedure17 to ??, 17, ?? to 17disk formattingdefined5disk initializationdefined4disk initialization dialog boxcustomizing text for reinitializing disks11initializing disks without12 to 14placement of11presentation of5 to 7variations in6Disk Initialization Package3 to 24loading10, 17low-level routines20 to 22overriding the disk initialization dialog box12 to 14routines in16 to 22unloading17 to 18disk initialization warning dialog6disk naming dialog6disk verificationdefined5disk zeroingdefined5disk-inserted eventsmasking out9receiving in a modal dialog10responding to9 to 11disksdetermining whether disk is valid10erasing11 to 12erasing in the Finder7formatting20 to 21initializing9 to 11overriding the disk initialization dialog box12 to 14naming6reinitializing11 to 12verifying formatting of21DIUnload procedure17 to ??, 17, ?? to 18DIVerify function21DIZero function21 to ??, 21, ?? to 22FFIle Managerand bad block sparing8File Managermounting inserted disks9FmtDefaults global variable14formatting disks20 to 21HHFSDefaults data structure14 to 15Iinitializing disks3 to 6, 9 to 11overriding the disk initialization dialog box12 to 14Nnaming disks6PPack2 trap macro24Ssignature wordsdefault for hierarchical volumes15Special menuErase Disk command7Standard File Packageand disk initialization5Uuser interfacefor initializing and naming a disk5 to 7Vverifying formatting of disks21volume characteristicschanging defaults14 to 16reverting back to defaults16Zzeroing a disk.See disk zeroing5zzabSize field15zzbtClpSize field15zzclpSize field15zznxFreeFN field15zzsigWord field15The Alias ManagerAbout the Alias Manager5-3Alias Records5-4Search Strategies5-5Relative Searches5-5Absolute Searches5-6Fast Searches5-7Exhaustive Searches5-8Using the Alias Manager5-8Creating Alias Records5-9Resolving Alias Records5-10Identifying a Single Target5-10Identifying Multiple Targets5-11Maintaining Alias Records5-11Getting Information About Alias Records5-12Customizing Alias Records5-13Reference to the Alias Manager5-13Data Structures5-13Alias Records5-13Routines5-14Creating and Updating Alias Records5-14Resolving and Reading Alias Records5-17Filtering Possible Targets5-23Summary of the Alias Manager5-255The Alias ManagerThis chapter describes how your application can use the Alias Manager to establish and resolve alias records, which are data structures that describe file system objects (that is, files, directories, and volumes). You create an alias record to take a “fingerprint” of a file system object, usually a file, that you might need to locate again later. You can store the alias record, instead of a file system specification, and then let the Alias Manager find the file again when it’s needed. The Alias Manager contains algorithms for locating files that have been moved, renamed, copied, or restored from backup. The Alias Manager lets you manage alias records. It does not directly manipulate Finder aliases, which the user creates and manages through the Finder. The Finder Interface chapter in the Toolbox volume describes Finder aliases and ways to accommodate them in your application.<36pt\>\x12 <8bat\>uThe Alias Manager is available only in system software version 7.0 or later. Use the Gestalt function, described in the chapter “Compatibility Guidelines” of the Overview volume, to determine whether the Alias Manager is present.Read this chapter if you want your application to create and resolve alias records. You might store an alias record, for example, to identify a customized dictionary from within a word-processing document. When the user runs a spelling checker on the document, your application can ask the Alias Manager to resolve the record to find the correct dictionary.To use this chapter, you should be familiar with the File Manager’s conventions for identifying files, directories, and volumes, as described in the Introduction to File Management chapter in this volume.This chapter begins with a description of the Alias Manager, alias records, and the search strategies that the Alias Manager uses to resolve (that is, find the target of) an alias record. Then this chapter shows how you cann    create alias recordsn    resolve alias recordsn    store alias records as resourcesn    get information about the target of an alias recordAbout the Alias ManagerThe Alias Manager creates and resolves alias records. In general, you should use the Alias Manager to create an alias record whenever you find yourself storing a specific file description, such as filename and parent directory ID. The Alias Manager stores this information and more in the alias record, and it also provides a set of search strategies for resolving the record later. The search strategies are described later in this chapter in “Search Strategies.” You can use the Alias Manager to create, resolve, and (if necessary) update alias records. You can also obtain information about the target of an alias record without actually resolving the alias record.The Alias Manager can track files and directories across volumes. If the target of an alias record is on an unmounted AppleShare volume, the Alias Manager automatically mounts the volume when it resolves the alias. If the target object is on an unmounted ejectable volume, the Alias Manager prompts the user to insert the volume.When the Alias Manager creates an alias record, it allocates the storage, fills in the record, and returns a handle to it. Your application is responsible for storing the record and retrieving it when needed. Your application must also supply strategies for handling various alias-resolution problems, described in “Resolving Alias Records” later in this chapter.To help you understand and use the Alias Manager, this section providesn    an overview of alias recordsn    a description of the search strategies the Alias Manager uses to resolve alias recordsAlias RecordsAn alias record is a data structure that describes a file, directory, or volume. The record containsn    location information, such as name and parent directory IDn    verification information, such as creation date, file type, and creatorn    volume mounting information (that is, server and zone), if applicableBy storing alias records, you can allow your users to create a robust connection to a file—that is, a connection that can survive the moving or renaming of the target file. The Finder introduced in system software version 7.0, for example, stores alias records in aliases created by the user to represent other files or folders. The Edition Manager uses alias records to support data sharing among separate documents.An alias record is a reliable way to identify a file system object when your application is communicating with a process that might be running on a different machine.The creation of an alias record has no effect on the target of the record, except to establish a file ID reference for the target file if one did not previously exist. (See the chapter “The File Manager” in this volume for a description of file IDs and file ID references.)The alias record contains only two fields of public information available to your application. The bulk of the record is managed privately by the Alias Manager.TYPE AliasRecord =                RECORD                    userType:                OSType;                    {application's signature}                    aliasSize:                Integer                    {size of record when created}                    {variable-length private data}                END;Your application can store, in the userType field, its own signature or any other data that fits into 4 bytes. When the Alias Manager creates an alias record, it stores 0 in that field.The Alias Manager stores, in the aliasSize field, the size assigned to the record at the time of its creation. Knowing the starting size allows you to store and retrieve data of your own at the end of the record (see “Customizing Alias Records” later in this chapter). An alias record is typically 200 to 300 bytes long.The private Alias Manager data includes all of the location, verification, and mounting information needed to resolve the alias record with the various search strategies described in this chapter.Search StrategiesOne of the key features of the Alias Manager is the search strategies built into the alias-resolution functions. The search strategies are designed to find the original target of an alias record, even if the target has been moved, renamed, copied, or restored from backup. Which strategy you use to resolve a particular alias record usually depends on a number of factors, including whether you are willing to sacrifice time to find as many potential targets as possible and whether the target is known to be in a particular volume.You can request either a relative or an absolute search. If you request an absolute search, you can specify whether the search should be either fast or exhaustive. (A relative search is always a fast search.) As you can see, there are three general search strategies available to your application for resolving alias records:n    relative search (always fast)n    absolute fast searchn    absolute exhaustive searchThe following sections describe these search strategies.Relative SearchesA relative search starts in a specified directory and searches for the target of an alias record by ascending the file system hierarchy to a predetermined common parent of the target and the starting directory and then descending the hierarchy from that common parent.Suppose, for example, that you are writing a word-processing application that allows the user to build a customized, supplemental dictionary for each document. You might create the dictionary as a separate document in the same directory as the document it serves. In this case, the common parent of the document and the dictionary file (that is, the lowest-level directory that appears in the pathnames of both) is simply the directory containing both files.More generally, you might want to store all document-specific dictionary files in their own directory, as illustrated in Figure 5-1. Here, the common parent of the document file Doc 2 and its associated dictionary file Dict 2 is the directory named Sample.Resolving a relative pathTo resolve an alias record using a relative search, the Alias Manager needs several pieces of information, which are recorded in the alias record at the time you create it. The Alias Manager needs a relative path, that is, a path to the target from another file or directory on the same volume. (Relative paths don’t work across volumes.) To record a relative path, the Alias Manager saves the distances from the target and the starting file or directory to their common parent. The Alias Manager can later use those distances in conjunction with the full pathname to conduct a relative search.When resolving the alias record by using a relative path, the Alias Manager looks at the directory that is the specified distance above the starting file or directory. The Alias Manager then constructs a partial pathname by extracting one field of the absolute pathname for each step from the target to the common parent. In Figure 5-1, the distance is 2, so the partial pathname is Dictionaries:Dict 2.Absolute SearchesIn contrast to a relative search, an absolute search always begins at the root directory of the file system hierarchy and always descends the hierarchy. The first step in any absolute search is to identify the volume on which the target resides. When conducting a volume search, the Alias Manager considers the volume’s name, its creation date (which acts almost as a unique identifier for a volume), and its type (for example, a hard disk, a 3.5-inch floppy disk, or an AppleShare volume).The Alias Manager first looks for a volume that matches all three criteria: name, creation date, and type. The search succeeds if the volume is mounted and if its name and creation date have not changed since the record was created. If the search fails, the Alias Manager attempts to match by creation date and type only. This step locates volumes that have been renamed. Finally, the Alias Manager attempts to match by volume name and type only.If the target is on an unmounted AppleShare volume, the Alias Manager attempts to mount the volume. It presents a name and password dialog box if appropriate. If the target is on an unmounted ejectable volume, the Alias Manager displays a dialog box prompting the user to insert the volume. Your application can suppress the automatic mounting, as explained in the description of the MatchAlias function in “Resolving and Reading Alias Records” later in this chapter.In some circumstances, a relative search identifies the correct target when an absolute search cannot. For example, suppose the user of your word-processing application creates a working copy of a document and dictionary by copying the entire folder Sample to another disk. The user later updates the original document and dictionary by copying the folder from the working disk. All of the underlying file and directory identifications change, but the filenames and relative path remain the same. When the user later runs the spelling checker on the document, a relative-path search finds the correct target dictionary.Fast SearchesA fast search employs an algorithm designed to find the target of an alias record quickly. Depending on how you invoke it, the fast-search algorithm starts with either a relative search or an absolute search. The Alias Manager can perform a relative fast search whether or not it has identified the target volume, but it cannot perform an absolute fast search unless the volume has been identified. During an absolute fast search, the Alias Manager first searches by file ID (if the target is a file) or directory ID (if the target is a directory). (File IDs and directory IDs are described in the File Manager chapter of this volume.) Even if a file has been renamed or moved on a volume, the Alias Manager can find it quickly through its file ID.If the search by file ID or directory ID fails, the Alias Manager searches by name in the original parent directory. This search locates the target if its file or directory ID has changed but it still exists by the same name in the parent directory (for example, if the target was restored from a backup). The Alias Manager compares file numbers on files found by name in the correct parent directory. If the file numbers do not match, the file is treated as a possible match—that is, it is put on the list of candidates—and the search continues. If the target is not found by name in the parent directory, the Alias Manager looks for a file by file number in the parent directory. A file with the same file number but a different name replaces a file with the same name but a different file number in the list of matches.If the search by file ID or directory ID fails and if the Alias Manager cannot find the original parent directory, it searches for the target by full pathname. This search finds the target if it resides in the same location on the volume but the directory ID of its parent directory has changed (for example, if the entire parent directory was restored from a backup).If the search by full pathname fails, the Alias Manager attempts to find the file by tracing partial pathnames up through all parent directories, using parent directory IDs instead of directory names. For example, consider this full pathname:Loma Prieta:MyReports:October:Sales ReportIf the search by full pathname fails, Alias Manager first looks for the partial pathname :Sales Report in the directory with the ID that the directory Loma Prieta:MyReports:October had when the alias record was created. If that search fails, it looks for :October:Sales Report in the directory with the ID that Loma Prieta:MyReports had, and so on.If you do not ask for a search by relative path first but do provide a starting point for a relative search, and if the alias record contains relative path information, the Alias Manager performs a relative search after the absolute search. The relative search succeeds if the relative path is the same as when the record was created and if the names of the target and its intervening parent directories have not changed.Exhaustive SearchesAn exhaustive search uses an algorithm that scans an entire volume to look for possible matches. The Alias Manager typically performs an exhaustive search by calling the File Manager function PBCatSearch, searching for files or directories with a matching creation date, creator, and type. (See the chapter “The File Manager” in this volume for a description of PBCatSearch.)The PBCatSearch function is available only on volumes that support the HFS routines and only on systems running system software version 7.0 and later. When PBCatSearch is not available, an exhaustive search of the entire volume is performed by making a series of indexed File Manager calls, searching for objects with matching creation date, type, creator, or file number.Using the Alias ManagerYou use the Alias Manager primarily to create and resolve alias records. You can also use it to get information about and update alias records.The Alias Manager creates an alias record in memory and provides you with a handle to the record. When you no longer need a record in memory, free the memory by calling the DisposHandle procedure, described in the Memory Manager chapter of this volume. You can store and retrieve alias records as resources of type 'alis'.Alias Manager functions accept and return file specifications in the form of FSSpec records, which contain a volume reference number, a parent directory ID, and a target name. See the chapter “The File Manager” in this volume for a description of file identification conventions.Before calling any of the Alias Manager functions, you should verify that the Alias Manager is available by calling the Gestalt function with a selector of gestaltAliasMgrAttr. If Gestalt sets the gestaltAliasMgrPresent bit in the response parameter, the Alias Manager is present. For a complete description of the Gestalt function, see the Compatibility Guidelines chapter of the Overview volume.For more detailed descriptions of the functions described in this section, see “Reference to the Alias Manager” later in this chapter.Creating Alias RecordsYou create a new alias record by calling one of three functions: NewAlias, NewAliasMinimal, or NewAliasMinimalFromFullPath. The NewAlias function creates a complete alias record that can make full use of the alias-resolution algorithms. The other two functions are streamlined variations designed for circumstances when speed is more important than robust resolution services. All three functions allocate the memory for the record, fill it in, and return a handle to it.The NewAlias function always records the name and the file or directory ID of the target, its creation date, the parent directory name and ID, and the volume name and creation date. It also records the full pathname of the target and a collection of other information. You can have NewAlias store relative path information as well by supplying a starting point for a relative path (see “Relative Searches” earlier in this chapter for a description of relative paths).Call NewAlias when you want to create an alias record to store for later use. For example, suppose you are writing a word-processing application that allows the user to customize a dictionary for use with a single text file. Your application stores the custom data in a separate dictionary file in the same directory as the document. As soon as you create the dictionary file, you can call NewAlias to create an alias record for that file, including path information relative to the user’s text file. Listing 5-1 shows how use NewAlias to create a new alias.Creating an alias recordFUNCTION DoCreateAlias (myDoc, myDict: FSSpec): OSErr;VAR    myAliasHdl:                AliasHandle;                        {handle to created alias}    myErr:                OSErr;BEGIN    myErr := NewAlias(@myDoc, myDict, myAliasHdl);                                                                {create alias record}    IF myAliasHdl <> NIL THEN        myErr := DoSaveAlias(myDoc, myAliasHdl);                                                            {save it as a resource}    DoCreateAlias := myErr;                                                                {return result code}END;The function DoCreateAlias defined in Listing 5-1 takes two FSSpec records as parameters. The first specifies the document that is to serve as the starting point for a relative search, in this case the user’s text file. The second FSSpec record specifies the target of the alias to be created, in this example the dictionary file. DoCreateAlias calls NewAlias to create the alias record; if successful, it calls the application-defined function DoSaveAlias to save the alias record as a resource in the document file’s resource fork. See Listing 5-2 for a definition of DoSaveAlias.The two variations on the NewAlias function, NewAliasMinimal and NewAliasMinimalFromFullPath, record only a minimum of information about the target. The NewAliasMinimal function records only the target’s name, parent directory ID, volume name and creation date, and volume mounting information. The NewAliasMinimalFromFullPath function records only the full pathname of the target, including the volume name.Use NewAliasMinimal or NewAliasMinimalFromFullPath when you are willing to give up robust alias-resolution service in return for speed. The Finder, for example, stores minimal aliases in the Apple events that tell your application to open or print a document. Because the alias record is resolved almost immediately, the description is likely to remain valid, and the shorter record is probably safe.You can use NewAliasMinimalFromFullPath to create an alias record for a target that doesn’t exist or that resides on an unmounted volume.Resolving Alias RecordsThe Alias Manager provides two functions that you can use to resolve alias records:n    the high-level function ResolveAlias, which performs a fast search and identifies only one targetn    the low-level function MatchAlias, which can perform a fast search, an exhaustive search, or both, and which can return a list of target candidatesIn general, when you want to identify only the single most likely target of an alias record, you call ResolveAlias. You call MatchAlias when you want your program to control the search.Identifying a Single TargetTo resolve an alias record, you usually call the ResolveAlias function. This function performs a fast search (described earlier in “Fast Searches”) and exits after it identifies one target. The ResolveAlias function compares some key information about the identified target with the information stored in the alias record. If any of the information is different, ResolveAlias automatically updates the record.Like all other Alias Manager functions, ResolveAlias updates the record only in memory. Your application is responsible for updating alias records stored on disk when appropriate.<36pt\>\x12 <8bat\>uIn the dictionary example illustrated in Figure 5-1 earlier in this chapter, the application calls ResolveAlias with a relative path specification when the user runs the spelling checker on a document with a customized dictionary. If you provide a relative starting point, ResolveAlias performs the relative search first.The ResolveAlias function uses the wasChanged parameter to report whether it updated the alias record. After ResolveAlias runs, the value of wasChanged is TRUE if the record was updated and FALSE if it was not. If you are storing the alias record, check the value of wasChanged (as well as the function’s result code) to see whether to update the stored record after resolving an alias.If ResolveAlias can’t resolve the alias record, it returns a nonzero result code. A result code of fnfErr signals that ResolveAlias has found the correct volume and parent directory but not the target file or folder. In this case, ResolveAlias constructs a valid FSSpec record that describes the target. You can use this record to explore possible solutions to the resolution failure. You can, for example, use the FSSpec record to create a replacement for a missing file with the File Manager function FSpCreate.Identifying Multiple TargetsThe MatchAlias function is a low-level routine that gives your application control over the search algorithms.You can controln    whether to attempt an automatic mounting of unmounted volumesn    whether to search on more than one volumen    whether to perform a fast search, an exhaustive search, or bothn    what the order of the absolute and relative searches in a fast search should ben    whether to pursue search strategies that require interaction with the user (such as asking for a password while mounting an AppleShare volume)You can also specify a maximum number of candidates that MatchAlias can identify. See “Resolving and Reading Alias Records” later in this chapter for details about controlling a search with the MatchAlias function.You can supply an optional filter function that MatchAlias callsn    each time it identifies a possible matchn    when three seconds have elapsed without a matchThe filter function determines whether each candidate is added to the list of possible targets. It can also terminate the search. See “Filtering Possible Targets” later in this chapter for a description of the filter function.MatchAlias returns, in an array of file system specification records, all candidates that it identifies.Maintaining Alias RecordsYou can store alias records as resources of type 'alis'.CONST                    rAliasType = 'alis';                            {resource type for saved alias records}To store and retrieve resources, use the standard Resource Manager functions (AddResource, GetResource, and GetNamedResource) described in the Resource Manager chapter of the Toolbox volume. Listing 5-2 illustrates one way to save an alias record as a resource in a document file’s resource fork.Storing an alias record as a resourceFUNCTION DoSaveAlias (myDoc: FSSpec; myAliasHdl: AliasHandle): OSErr;VAR    myErr: OSErr;    myFile: Integer;                                    {file ref number of document's resource fork}CONST    kID = 129;    kName = 'Dictionary Alias';BEGIN    myFile := FSpOpenResFile(myDoc, fsCurPerm);    IF myFile = -1 THEN                                    {couldn't open the document's resource fork}        BEGIN            DoSaveAlias := ResError;            exit(DoSaveAlias);        END;    AddResource(Handle(myAliasHdl), rAliasType, kID, kName);    myErr := ResError;                                    {check for errors adding resource}    IF myErr = noErr THEN        BEGIN            WriteResource(Handle(myAliasHdl));            myErr := ResError;                            {check for errors writing resource}        END;    DoSaveAlias := myErr;END;Note that DoSaveAlias assumes that the file specified by the myDoc parameter already has a resource fork and that the file is not yet open. Your application might have different requirements.To update an alias record, use the UpdateAlias function. You typically call UpdateAlias any time you know that the target of an alias record has been renamed or otherwise changed. You are most likely to call UpdateAlias after a call to the MatchAlias function. If MatchAlias identifies a single target, it sets a flag telling you whether or not the key information about the target file matches the information in the alias record. It is the responsibility of your application to update the record.The ResolveAlias function automatically updates an alias record if any of the key information about the identified target does not match the information in the record.Getting Information About Alias RecordsTo retrieve information from an alias record without actually resolving the record, call the GetAliasInfo function. You can use GetAliasInfo to retrieve the name of the target, the names of the target’s parent directories, the name of the target’s volume, or, in the case of an AppleShare volume, its zone or server name.Customizing Alias RecordsAn alias record contains two kinds of information: public information available to your application and private information available only to the Alias Manager. Your application can use the first field, userType, to store its own signature or any other data that fits into 4 bytes. Your application can use the second field, aliasSize, to customize the alias record for storing additional data.The Alias Manager stores the size of the record when it is created or updated in the aliasSize field. To customize an alias record, you first use the SetHandleSize procedure, described in the chapter “The Memory Manager” in this volume, to increase the size of the record. You can then find the starting address of your own data in the record by adding the record’s starting address to the length recorded in the aliasSize field. If you use the Memory Manager to expand the record, the Alias Manager preserves your data, even if it changes the size of its own data when updating the record.In general, you should customize only alias records that you have created.<36pt\>\x12 <8bat\>uReference to the Alias ManagerThis section describes the routines provided by the Alias Manager and the AliasRecord data structure you must pass when calling those routines.Data StructuresThe Alias Manager uses alias records to store information that allows it to locate an object in the file system.Alias RecordsAlias records are defined by the AliasRecord data type.TYPE                    AliasRecord                    =RECORD                userType:                OSType;                    {application's signature}                aliasSize:                Integer;                    {size of record when created}                {variable-length private data}END;userType    A 4-byte field that can contain application-specific data. When an alias record is created, this field contains 0. Your application can use this field for its own purposes. Typically you should store your application’s signature here.aliasSize    The size in bytes assigned to the alias record at the time of its creation. This is the total size of the record, including the userType and aliasSize fields, as well as the variable-length data that is private to the Alias Manager. If you customize an alias record by appending additional data to the end of the record, you are responsible for updating the aliasSize field accordingly.Following these two fields is a variable-length block of data maintained privately by the Alias Manager.RoutinesThis section describes the routines you use to create, update, resolve, and read alias records. Alias Manager routines use file system specification records (FSSpec records) to identify files, directories, and volumes. To create an FSSpec record, call the function FSMakeFSSpec, described in the File Manager chapter of this volume.The Alias Manager routines can return the result codes listed in this section or any other applicable file system or memory management result codes.Creating and Updating Alias RecordsYou can use the functions NewAlias, NewAliasMinimal, NewAliasMinimalFromFullPath, and UpdateAlias to create and update alias records.5NewAliasYou use the NewAlias function to create a complete alias record.FUNCTION NewAlias (fromFile: FSSpecPtr; target: FSSpec;                            VAR alias: AliasHandle): OSErr;fromFile    The starting point for a relative path, to be used later in a relative search. If you do not need relative path information in the record, pass a fromFile value of NIL. If you want NewAlias to record relative path information, pass a pointer to a valid FSSpec record in this parameter. The two files or directories, fromFile and target, must reside on the same volume.target    An FSSpec record for the target of the alias record.alias    A handle to the newly created alias record. If the function fails to create an alias record, it sets alias to NIL.DESCRIPTIONNewAlias creates an alias record that describes the specified target. It allocates the storage, fills in the record, and puts a record handle to that storage in the alias parameter. The NewAlias function always records the name and file or directory ID of the target, its creation date, the parent directory name and ID, and the volume name and creation date. It also records the full pathname of the target and a collection of other information relevant to locating the target, verifying the target, and mounting the target’s volume, if necessary. You can have NewAlias store relative path information as well by supplying a starting point for a relative path (see “Relative Searches” earlier in this chapter for a description of relative paths).RESULT CODESnoErr    0    No error5NewAliasMinimalYou use the NewAliasMinimal function to create a short alias record quickly.FUNCTION NewAliasMinimal (target: FSSpec;                                         VAR alias: AliasHandle): OSErr;target    An FSSpec record for the target of the alias record.alias    A handle to the newly created alias record. If the function fails to create an alias record, it sets alias to NIL.DESCRIPTIONNewAliasMinimal creates an alias record that contains only the minimum information necessary to describe the target: the target name, the parent directory ID, the volume name and creation date, and the volume mounting information. The NewAliasMinimal function uses the standard alias record data structure, but it fills in only parts of the record.The ResolveAlias function, described in “Resolving and Reading Alias Records” later in this chapter, never updates a minimal alias record.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No error5NewAliasMinimalFromFullPathYou use the function NewAliasMinimalFromFullPath to quickly create an alias record that contains only the full pathname of the target.FUNCTION NewAliasMinimalFromFullPath                        (fullPathLength: Integer; fullPath: Ptr;                             zoneName: Str32; serverName: Str31;                            VAR alias: AliasHandle): OSErr;fullPathLength    The number of characters in the full pathname of the target.fullPath    A pointer to a buffer that contains the full pathname of the target. The full pathname starts with the name of the volume, includes all of the directory names in the path to the target, and ends with the target name. (For a description of pathnames, see the chapter “The File Manager” in this volume.)zoneName    The AppleTalk zone name of the AppleShare volume on which the target resides. Set this parameter to a null string if you do not need it.serverName    The AppleTalk server name of the AppleShare volume on which the target resides. Set this parameter to a null string if you do not need it.alias    A handle to the newly created alias record. If the function fails to create an alias record, it sets alias to NIL.DESCRIPTIONNewAliasMinimalFromFullPath creates an alias record that identifies the target by full pathname. You can call NewAliasMinimalFromFullPath to create an alias record for a file that doesn’t exist or that resides on an unmounted volume. The NewAliasMinimalFromFullPath function uses the standard alias record data structure, but it fills in only the information provided in the input parameters. You can therefore use NewAliasMinimalFromFullPath to create alias records for targets on unmounted volumes.RESULT CODESnoErr    0    No error5UpdateAliasYou use the UpdateAlias function to update an alias record.FUNCTION UpdateAlias (fromFile: FSSpecPtr; target: FSSpec;                                    alias: AliasHandle;                                 VAR wasChanged: Boolean): OSErr;fromFile    The starting point for a relative path, to be used later in a relative search. If you do not need relative path information in the record, pass a fromFile value of NIL. If you want UpdateAlias to record relative path information, pass a pointer to a valid FSSpec record in this parameter.target    The target of the alias record. This parameter must be a valid FSSpec record.alias    A handle to the alias record to be updated.wasChanged    A Boolean value indicating whether the newly constructed alias record is exactly the same as the old one. If the new record is the same as the old one, UpdateAlias sets the wasChanged parameter to FALSE. Otherwise, it sets it to TRUE. Check this parameter to determine whether you need to save an updated record.DESCRIPTIONUpdateAlias updates the alias record pointed to by the alias parameter so that it describes the target specified by the target parameter. The UpdateAlias function rebuilds the entire alias record and fills it in as the NewAlias function would.UpdateAlias always creates a complete alias record. When you use UpdateAlias to update a minimal alias record, you convert the minimal record to a complete record.SPECIAL CONSIDERATIONSThe two files or directories, fromFile and target, must reside on the same volume.RESULT CODESnoErr    0    No errorparamErr    –50    The value of target or alias parameter, or of         both, is NIL, or the alias record is corruptResolving and Reading Alias RecordsYou can use the functions ResolveAlias and MatchAlias to resolve or find possible targets of an alias record. You can use the function GetAliasInfo to get information about the target of an alias without actually resolving the alias.5ResolveAliasYou use the ResolveAlias function to identify the single most likely target of an alias record. FUNCTION ResolveAlias (fromFile: FSSpecPtr; alias: AliasHandle;                                VAR target: FSSpec;                                 VAR wasChanged: Boolean): OSErr;fromFile    The starting point for a relative search. If you pass a fromFile parameter of NIL, ResolveAlias performs only an absolute search. If you pass a pointer to a valid FSSpec record in the fromFile parameter, ResolveAlias performs a relative search for the target, followed by an absolute search only if the relative search fails. If you want to perform an absolute search followed by a relative search, you must use the MatchAlias function.alias    A handle to the alias record to be resolved and, if necessary, updated.target    The target of the alias record. This parameter must be a valid FSSpec record.wasChanged    A Boolean value indicating whether the alias record to be resolved was updated because it contained some outdated information about the target.DESCRIPTIONResolveAlias performs a fast search for the target of the alias, as described earlier in “Fast Searches.” If the resolution is successful, ResolveAlias returns (in the target parameter) the FSSpec record for the target file system object, updates the alias record if necessary, and reports (through the wasChanged parameter) whether the record was updated. If the target is on an unmounted AppleShare volume, ResolveAlias automatically mounts the volume. If the target is on an unmounted ejectable volume, ResolveAlias asks the user to insert the volume. The ResolveAlias function exits after it finds one acceptable target.After it identifies a target, ResolveAlias compares some key information about the target with the information in the alias record. (The description of the MatchAlias function later in this section lists the key information.) If the information differs, ResolveAlias updates the record to match the target. If it updates the alias record, ResolveAlias sets the wasChanged parameter to TRUE. Otherwise, it sets it to FALSE. (ResolveAlias never updates a minimal alias, so it never sets wasChanged to TRUE when resolving a minimal alias.)When it finds the specified volume and parent directory but fails to find the target file or directory in that location, ResolveAlias returns a result code of fnfErr and fills in the target parameter with a complete FSSpec record describing the target (that is, the volume reference number, parent directory ID, and filename or folder name). The FSSpec record is valid, although the object it describes does not exist. This information is intended as a “hint” that lets you explore possible solutions to the resolution failure. You can, for example, use the FSSpec record and the File Manager function FSpCreate to create a replacement for a missing file.The ResolveAlias function displays the standard dialog boxes when it needs input from the user, such as a name and password for mounting a remote volume. The user can cancel the resolution through these dialog boxes.RESULT CODESnoErr    0    No errornsvErr    –35    The volume is not mountedfnfErr    –43    Target not found, but volume and parent        directory found; if the value of aliasCount is 1,        the target parameter contains a valid FSSpec        recordparamErr    –50    The value of target or alias parameter, or of         both, is NIL, or the alias record is corruptdirNFErr    –120    Parent directory not foundusrCanceledErr    –128    The user canceled the operation5MatchAliasYou use the MatchAlias function to identify a list of possible matches and pass the list through an optional selection filter. The filter can return more than one possible match.FUNCTION MatchAlias (fromFile: FSSpecPtr; rulesMask: LongInt;                            alias: AliasHandle; VAR aliasCount: Integer;                            aliasList: FSSpecArrayPtr;                             VAR needsUpdate: Boolean;                             aliasFilter: AliasFilterProcPtr;                            yourDataPtr: UNIV Ptr): OSErr;fromFile    The starting point for a relative search. If you do not want MatchAlias to perform a relative search, set fromFile to NIL. If you want MatchAlias to perform a relative search, pass a pointer to a file system specification record that describes the starting point for the search.rulesMask    A set of rules to guide the resolution. Pass the sum of all of the rules you want to invoke.alias    A handle to the alias record to be resolved.aliasCount    On input, the maximum number of possible matches to return. On output, the actual number of matches returned.aliasList    A pointer to the array that holds the results of the search.needsUpdateA Boolean flag that indicates whether the alias record to be resolved needs to be updated.aliasFilter    An application-defined filter function.yourDataPtrA pointer to data to be passed to the filter function.DESCRIPTIONMatchAlias resolves the alias record specified by the alias parameter, following the rules specified by the rulesMask parameter. Then it returns, in the structure specified by the aliasList parameter, a list of possible candidates. The MatchAlias function places the number of candidates identified in the aliasCount parameter.You specify the matching criteria by passing a sum of these constants in the rulesMask parameter.CONST                kARMMountVol                        =    $00000001;                {mount volume automatically}                kARMNoUI                        =    $00000002;                {suppress user interface}                kARMMultVols                        =    $00000008;                {search on multiple volumes}                kARMSearch                        =    $00000100;                {do a fast search}                kARMSearchMore                        =    $00000200;                {do an exhaustive search}                kARMSearchRelFirst                        =    $00000400;                {do a relative search first}Constant descriptionskARMMountVol    Automatically try to mount the target’s volume if it is not already mounted.kARMNoUI    Stop if a search requires user interaction, such as a password dialog box when mounting a remote volume. If user interaction is needed and kARMNoUI is in effect, the search fails. kARMMultVols    Search all mounted volumes. The search begins with the volume on which the target resided when the record was created. When you specify a fast search of all mounted volumes, MatchAlias performs a formal fast search only on the volume described in the alias record. On all other volumes it looks for the target by ID or by name in the directory with the specified parent directory ID. When you specify an exhaustive search of multiple volumes, MatchAlias performs the same search on all volumes. When resolving an alias record created by NewAliasMinimalFromFullPath, MatchAlias ignores this flag. kARMSearch    Perform a fast search for the alias target. If kARMSearchRelFirst is not set, perform an absolute search first, followed by a relative search only if the value of the fromFile parameter is not NIL and the list of matches is not full. kARMSearchMore    Perform an exhaustive search for the alias target. On HFS volumes, the exhaustive search uses the File Manager function PBCatSearch to identify candidates with matching creation date, type, and creator. The PBCatSearch function is available only on HFS volumes and only on systems running version 7.0 or later. On MFS volumes or HFS volumes that do not support PBCatSearch, the exhaustive search makes a series of indexed calls to File Manager functions, using the same search criteria. If you set kARMSearchMore and one or both of kARMSearch and kARMSearchRelFirst, MatchAlias performs the fast search first. kARMSearchRelFirst    If kARMSearch is also set, perform a relative search before the absolute search. (If kARMSearch is also set and the target is found through the absolute search, MatchAlias sets the needsUpdate flag to TRUE.) If neither kARMSearch nor kARMSearchMore is set, perform only a relative search. If kARMSearch is not set but kARMSearchMore is set, perform a relative search followed by an exhaustive search.You must specify at least one of the last three parameters: kARMSearch, kARMSearchMore, and kARMSearchRelFirstYour application can specify a maximum number of possible matches by setting the aliasCount parameter. MatchAlias changes the aliasCount parameter to the actual number of candidates identified. If MatchAlias finds the parent directory on the correct volume but does not find the target, it sets the aliasCount parameter to 1, puts the file system specification record for the target in the results list, and returns fnfErr. The FSSpec record is valid, although the object it describes does not exist. This information is intended as a “hint” that lets you explore possible solutions to the resolution failure. You can, for example, use the FSSpec record and the File Manager function FSpCreate to create a replacement for a missing file.The needsUpdate flag is a signal to your application that the record might need to be updated. After it identifies a target, MatchAlias compares some key information about the target with the same information in the record. If the information does not match, MatchAlias sets the needsUpdate flag to TRUE. The key information isn    the name of the targetn    the directory ID of the target’s parentn    the file ID or directory ID of the targetn    the name and creation date of the volume on which the target residesThe MatchAlias function also sets the needsUpdate flag to TRUE if it identifies a list of possible matches rather than a single match or if kARMsearchRelFirst is set but the target is identified through either an absolute search or an exhaustive search. Otherwise, the MatchAlias function sets the needsUpdate flag to FALSE. MatchAlias always sets the needsUpdate flag to FALSE when resolving an alias created by NewAliasMinimal. If you want to update the alias record to reflect the final results of the resolution, call UpdateAlias.The aliasFilter parameter points to a filter function supplied by your application. The Alias Manager executes this function each time it identifies a possible match and after the search has continued for three seconds without a match. Your filter function returns a Boolean value that determines whether the possible match is discarded (TRUE) or added to the list of possible targets (FALSE). It can also terminate the search by setting the variable parameter quitFlag. See “Filtering Possible Targets” later in the chapter for a description of the filter function.The yourDataPtr parameter can point to any data that your application might need in the filter function.RESULT CODESnoErr    0    No errornsvErr    –35    The volume is not mountedfnfErr    –43    Target not found, but volume and parent        directory found; if the value of aliasCount is 1,        the target parameter contains a valid FSSpec        recordparamErr    –50    The value of target or alias parameter, or of         both, is NIL, or the alias record is corruptusrCanceledErr    –128    The user canceled the operation5GetAliasInfoYou use the GetAliasInfo function to get information from an alias record without actually resolving the record.FUNCTION GetAliasInfo (alias: AliasHandle; index: AliasInfoType;                                VAR theString: Str63): OSErr;alias    A handle to the alias record to be read.index    The kind of information to be retrieved.theString    A string that holds the requested information.DESCRIPTIONGetAliasInfo retrieves the information specified by the index parameter from the record pointed to by the alias parameter and places that information in the parameter theString.The index parameter specifies the kind of information to be retrieved. If the value of index is a positive integer, GetAliasInfo retrieves the parent directory that has the same hierarchical level above the target as the index parameter (for example, an index value of 2 returns the name of the parent directory of the target’s parent directory). You can therefore assemble the names of the target and all of its parent directories by making repeated calls to GetAliasInfo with incrementing index values, starting with a value of 0. When the value of index is greater than the number of levels between the target and the root, GetAliasInfo returns an empty string. You can also set the index parameter to one of the following five values:.CONST                asiZoneName                            =    –3;            {get zone name}                asiServerName                            =    –2;            {get server name}                asiVolumeName                            =    –1;            {get volume name}                asiAliasName                            =    0;            {get target name}                asiParentName                            =    1;            {get parent directory name}Constant descriptionsasiZoneName    If the record represents a target on an AppleShare volume, retrieve the server’s zone name. Otherwise, return an empty string.asiServerName    If the record represents a target on an AppleShare volume, retrieve the server name. Otherwise, return an empty string.asiVolumeName    Return the name of the volume on which the target resides.asiAliasName    Return the name of the target.asiParentName    Return the name of the parent directory of the target of the record. If the target is a volume, return the volume name.The GetAliasInfo function returns the information stored in the alias record, which might not be current. To ensure that the information is current, you can resolve and update the alias record before calling GetAliasInfo.GetAliasInfo cannot provide all kinds of information about a minimal alias.<36pt\>\x12 <8bat\>uRESULT CODESnoErr    0    No errorparamErr    –50    The value of alias or theString parameter, or        of both, is NIL; the value of index is less than        the value of asiZoneName; or the alias record is         corruptFiltering Possible TargetsYou can write your own filter function to examine possible targets identified by the MatchAlias function. The MatchAlias function calls your filter function each time it identifies a possible match and when three seconds have elapsed without a match.The filter function takes three parameters and returns a Boolean value:FUNCTION MyMatchAliasFilter (cpbPtr: CInfoPBPtr;                                         VAR quitFlag: Boolean;                                         myDataPtr: Ptr): Boolean;The cpbPtr parameter points to the catalog information parameter block record (as returned by the File Manager function PBGetCatInfo) of the possible match. The MatchAlias function sets this parameter to NIL if it is calling your function to give it the periodic chance to terminate the search. (Do not use this pointer without checking for NIL.)Your filter function sets the quitFlag parameter to terminate the search.The myDataPtr parameter points to any customized data that your application passed when it called MatchAlias. This parameter allows your filter function to access any data that your application has set up on its own.The Boolean return value determines whether the possible match is discarded (TRUE) or added to the list of possible targets (FALSE).Summary of the Alias ManagerConstantsCONST        {Gestalt constants}    gestaltAliasMgrAttr                                = 'alis';                    {Alias Mgr attributes selector}    gestaltAliasMgrPresent                                = 0;                    {Alias Mgr is present}    {alias record resource type}    rAliasType                                = 'alis';    {alias resolution action rules masks for MatchAlias}    kARMMountVol                                =    $00000001;                {mount volume automatically}    kARMNoUI                                =    $00000002;                {suppress user interface}    kARMMultVols                                =    $00000008;                {search on multiple volumes}    kARMSearch                                =    $00000100;                {do a fast search}    kARMSearchMore                                =    $00000200;                {do an exhaustive search}    kARMSearchRelFirst                                =    $00000400;                {do a relative search first}    {index values for GetAliasInfo}    asiZoneName                                =    –3;                {get zone name}    asiServerName                                =    –2;                {get server name}    asiVolumeName                                =    –1;                {get volume name}    asiAliasName                                =    0;                {get target name}    asiParentName                                =    1;                {get parent directory name}Data TypesTYPE    AliasRecord                    =                            {alias record}    RECORD        userType:                OSType;                            {application's signature}        aliasSize:                Integer;                            {size of record when created}        {variable-length private data}    END;    AliasHandle                    =    ^AliasPtr;    AliasPtr                    =    ^AliasRecord;    AliasInfoType                            =    Integer;                {alias record information type}    AliasFilterProcPtr                            =    ProcPtr;                {application-defined routine}RoutinesCreating and Updating Alias RecordsFUNCTION NewAlias    (fromFile: FSSpecPtr; target: FSSpec;VAR alias: AliasHandle): OSErr;FUNCTION NewAliasMinimal    (target: FSSpec; VAR alias: AliasHandle): OSErr;FUNCTION NewAliasMinimalFromFullPath    (fullPathLength: Integer; fullPath: Ptr; zoneName: Str32; serverName: Str31; VAR alias: AliasHandle) : OSErr;FUNCTION UpdateAlias    (fromFile: FSSpecPtr; target: FSSpec; alias: AliasHandle; VAR wasChanged: Boolean): OSErr;Resolving and Reading Alias RecordsFUNCTION ResolveAlias    (fromFile: FSSpecPtr; alias: AliasHandle; VAR target: FSSpec; VAR wasChanged: Boolean): OSErr;FUNCTION MatchAlias    (fromFile: FSSpecPtr; rulesMask: LongInt; alias: AliasHandle; VAR aliasCount: Integer; aliasList: FSSpecArrayPtr; VAR needsUpdate: Boolean; aliasFilter: AliasFilterProcPtr; yourDataPtr: UNIV Ptr): OSErr;FUNCTION GetAliasInfo    (alias: AliasHandle; index: AliasInfoType; VAR theString: Str63): OSErr;Application-Defined RoutineFUNCTION MyMatchAliasFilter    (cpbPtr: CInfoPBPtr; VAR quitFlag: Boolean; myDataPtr: Ptr): Boolean;Result CodesnoErr    0    No errornsvErr    –35    The volume is not mountedfnfErr    –43    Target not found, but volume and parent directory found;        if the value of aliasCount is 1, the target parameter contains a valid         FSSpec recordparamErr    –50    The value of the target or alias parameter, or of both, is NIL, or the         alias record is corruptdirNFErr    –120    Parent directory not foundusrCanceledErr    –128    The user canceled the operationAssembly-Language InformationAlias Record Data StructureuserType    4 bytes    file type of target filealiasSize    2 bytes    size of record in bytesIndexAAlias Manager3 to 27.See also alias recordsroutines in14 to 23testing for availability8alias records4 to 5contents4, 13creating9, 14 to 16customizing12defined3getting information about12private Alias Manager data5reading22relative path in6resolving5 to 8functions for10 to 11, 18 to 22storing and retrieving11updating12'alis' resource type8, 11AppleShare volumesautomatic mounting in resolution of alias records4Ccallback routines.See also status routines23with MatchAlias function23common parent in alias records6Ddirectory IDsin resolution of alias records7Ffast search for alias records?? to 8file filter functionsfor resolving aliases23file IDsin resolution of alias records7GGetAliasInfo function22 to 23MMatchAlias function11, 19NNewAlias function9, 14NewAliasMinimal function15NewAliasMinimalFromFullpath function16Rrecords, alias. See alias recordsrelative search for an alias record7, 8ResolveAlias function10, 18resource types'alis'11Ssearch strategies in resolution of alias records5 to 8absolute6exhaustive8fast7relative5Ttargetof an alias record3UUpdateAlias function12, 16Vvolumesidentifying in an alias resolution6ZzzaliasSize field5, 13zzasiAliasName constant23zzasiParentName constant23zzasiServerName constant23zzasiVolumeName constant23zzasiZoneName constant23zzgestaltAliasMgrAttr constant8zzgestaltAliasMgrPresent constant8zzkARMmountVol constant20zzkARMMultVols constant20zzkARMnoUI constant20zzkARMSearch constant21zzkARMSearchMore constant21zzkARMSearchRelFirst constant21zzrAliasType constant11zzuserType field5î@ˇ ˇˇˇˇ@
  2. ˇ·ˇ‚7^, Palatino.Ä(*
  3. 4^Hÿˇˇ≥>ˇ◊°dONLNdƒHÂ.(›HInside Macintosh:
  4. H    4H     H
  5. ˇ·ˇ‚7^°dONLNd‰HÉ* Files
  6. à∫ÿ4à∫ÿ4üªË °dONLNdˇˇ(ߪPreliminary Draft
  7. ∂ª‘4∂ª”4πª–l    °dONLNdˇˇ* Developer TÎ@°dONLNdˇˇ)0echnical Publications°dONLNdˇˇ(Àª© $P°dONLNdˇˇ)    Apple ComputerZ†°dONLNdˇˇ)C , Inc. 1992
  8. à∫ÿÄQ°dONLNdˇˇ(öªˇ™@ˇ ˇˇˇˇ@
  9. ˇ·ˇ‚7^
  10. 4⁄`˙º4^*¿∫, Palatino
  11. .°dONLNd\*h1+*ee‡°dONLNd\2hï)Apple Computer, Inc. °dONLNdz*Ü≠(É*© 1991, Apple Computer, Inc.°dONLNd5Ñ*ê*
  12. All rights reserved.°dONLNdJì*ü±* Printed in the United States of °dONLNdkù*©R*
  13. America.°dONLNdt¨*∏±*The Apple logo is a registered °dONLNdì∂*¬∂*
  14. trademark of Apple Computer, °dONLNd∞¿*â*
  15. Inc. Use of the “keyboard” °dONLNdà*÷∏*
  16.  Apple logo (Option-Shift-K) for °dONLNdÏ‘*‡∞*
  17. commercial purposes without °dONLNdfi*Í•*
  18. the prior written consent of ˇˇN∑°dONLNd&Ë*Ùπ*
  19. Apple may constitute trademark °dONLNdEÚ*˛∏*
  20. infringement and unfair compe-°dONLNdc¸*π*
  21. #tition in violation of federal and °dONLNdÜ*X*
  22. state laws.°dONLNdí*!ç*Apple Computer, Inc. °dONLNd®*+í*
  23. 20525 Mariani Avenue  °dONLNdø)*5†*
  24. Cupertino, CA  95014-6299°dONLNdŸ3*?g*
  25. 408-996-1010  °dONLNdËB*N≥*Apple, the Apple logo, APDA, °dONLNdL*Xò*
  26. AppleLink, AppleShare, °dONLNdV*bÇ*
  27. AppleTalk, Apple IIP@°dONLNd0XÉaå)YGS
  28. ù°dONLNd2Vçb≥)
  29. , A/UX, °dONLNd:`*l≤(i*EtherTalk, HyperCard, Hyper-°dONLNdVj*vπ*
  30.  Talk, ImageWriter, LaserWriter, °dONLNdvt*Ä•*
  31. LocalTalk, Mac, Macintosh, °dONLNdë~*ä∑*
  32. MPW, MultiFinder, SANE, and °dONLNd≠à*îµ*
  33. TokenTalk are registered trade-°dONLNdÃí*û≥*
  34. marks of Apple Computer, Inc.°dONLNdͰ*≠©*Apple Desktop Bus, Balloon °dONLNd´*∑≥*
  35. Help, Finder, KanjiTalk, Moof, ˇˇÁ˰dONLNd$µ*¡π*
  36. QuickDraw, ResEdit, TrueType, °dONLNdBø*Àµ*
  37. and Zhong-Wen Talk are trade-°dONLNd_…*’≥*
  38. marks of Apple Computer, Inc.°dONLNd}ÿ*‰ó*Helvetica and Times are °dONLNdñ‚*Óô*
  39. registered trademarks of °dONLNd∞Ï*¯Ç*
  40. Linotype Company.ˇˇ%~°dONLNd¬˚*π*"ITC Zapf Dingbats is a registered °dONLNd‰*¢*
  41. trademark of International °dONLNdˇ*ç*
  42. Typeface Corporation.°dONLNd**∞*MacPaint is a registered trade-°dONLNd4(*4§*
  43. mark of Claris Corporation.°dONLNdP7*C¥*NuBus is a trademark of Texas °dONLNdoA*Mb*
  44. Instruments.°dONLNd|P*\≥*!PostScript is a registered trade-°dONLNdùZ*fô*
  45. mark, and Illustrator is a °dONLNdπd*pØ*
  46. trademark, of Adobe Systems °dONLNd÷n*zf*
  47. Incorporated.ˇˇ3√°dONLNd‰}*âπ*"Sony is a registered trademark of °dONLNdá*ì{*
  48. Sony Corporation.°dONLNdñ*¢∑*UNIX is a registered trademark °dONLNd7†*¨∞*
  49. of UNIX System Laboratories, °dONLNdT™*∂:*
  50. Inc.4^…¿YˇˇÜW°dONLNdY\…hX(e… Simultaneously published in the °dONLNdyf…r>*
  51. United States and Canada.°dONLNdìé…öJ*(Limited Warranty on Media °dONLNd≠ò…§*
  52. and Replacement°dONLNdΩ©…µ3*Even though Apple has °dONLNd‘≥…ø.*
  53. reviewed this manual, û‡°dONLNdÍ≥.øP)eAPPLE ˇˇ±°dONLNdΩ……S(Δ…MAKES NO WARRANTY OR ˇ˛ùǰdONLNd«…”S*
  54. REPRESENTATION, EITHER °dONLNd—…›;*
  55. EXPRESS OR IMPLIED, °dONLNd0€…ÁE*
  56. WITH RESPECT TO THIS °dONLNdEÂ…ÒE*
  57. MANUAL, ITS QUALITY, °dONLNdZÔ…˚I*
  58. ACCURACY, MERCHANT-°dONLNdm˘…N*
  59. ABILITY, OR FITNESS FOR °dONLNdÖ…N*
  60. A PARTICULAR PURPOSE. °dONLNdõ…,*
  61. AS A RESULT, THIS °dONLNdÆ…#<*
  62. MANUAL IS SOLD “AS °dONLNd¬!…-C*
  63. IS,” AND YOU, THE PUR-°dONLNdÿ+…7M*
  64. CHASER, ARE ASSUMING °dONLNdÌ5…AF*
  65. THE ENTIRE RISK AS TO °dONLNd?…K(*
  66. ITS QUALITY AND °dONLNdI…U *
  67. ACCURACY.  °dONLNd Z…fO*IN NO EVENT WILL APPLE °dONLNd7d…pC*
  68. BE LIABLE FOR DIRECT, °dONLNdNn…z1*
  69. INDIRECT, SPECIAL, °dONLNdbx…ÑJ*
  70. INCIDENTAL, OR CONSE-°dONLNdwÇ…é;*
  71. QUENTIAL DAMAGES °dONLNdâå…òB*
  72. RESULTING FROM ANY °dONLNdùñ…¢O*
  73. DEFECT OR INACCURACY °dONLNd≤†…¨'*
  74. IN THIS MANUAL, {†°dONLNd¬†(¨H)_even if °dONLNd ™…∂E(≥…advised of the possibility of °dONLNdË¥…¿*
  75. such damages.  °dONLNd¯≈…—;*THE WARRANTY AND °dONLNd    œ…€=*
  76. REMEDIES SET FORTH °dONLNdŸ…ÂD*
  77. ABOVE ARE EXCLUSIVE °dONLNd0„…Ô3*
  78. AND IN LIEU OF ALL °dONLNdDÌ…˘**
  79. OTHERS, ORAL OR °dONLNdU˜…?*
  80. WRITTEN, EXPRESS OR °dONLNdj…˙*
  81.     IMPLIED. Ó`°dONLNds˙H)1No Apple dealer, °dONLNdÑ …)(…agent, or employee is °dONLNdõ…!4*
  82. authorized to make any °dONLNd≥…+A*
  83. modification, extension, or °dONLNd–)…5?*
  84. addition to this warranty.  °dONLNdÌ:…FI*Some states do not allow the °dONLNd    
  85. D…P:*
  86. exclusion or limitation of °dONLNd    &N…ZO*
  87.  implied warranties or liability °dONLNd    FX…dR*
  88.  for incidental or consequential °dONLNd    fb…n/*
  89. damages, so the above ˇˇpr°dONLNd    }l…xS*
  90.  limitation or exclusion may not °dONLNd    ùv…ÇG*
  91. apply to you. This warranty °dONLNd    πÄ…åP*
  92. !gives you specific legal rights, °dONLNd    ⁄ä…ñK*
  93. and you may also have other ˇˇ‘Ô°dONLNd    ˆî…†S*
  94.  rights which vary from state to °dONLNd
  95. û…™‡*
  96. state.4^h¿¯ˇ<@ˇ ˇˇˇˇ@
  97. ˇ·ˇ‚7^
  98. 4⁄∫˙,     Helvetica    .(‡∫Contents
  99. ‡(‡1ù)-‡)1(Ô∫Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)10/15/91(¯∫ Second line., Palatino        (#∫CHAPTER )~1ˇˇf|ˇÆ°dONLNd]∫{¨(t∫Introduction to File 
  100. ûHM4ûHM 5H5°dONLNdˇˇ*”Contents
  101. ˇ·ˇ‚7^ˇˇf|ˇÆ°dONLNd}∫õc(î∫
  102. Management
  103. °dONLNd \∫hÏ*— About Filest`°dONLNd-\h)G1-1°dONLNd1iƒuÔ(rƒ
  104. File Forksχ°dONLNd=iu)?1-2°dONLNdAvƒÇË(ƒ    File Size@°dONLNdLv˝Ç
  105. )91-4°dONLNdPɃè÷(åƒFile À °dONLNdUÉ÷è7)Access Characteristics}¿°dONLNdmÉLèY)v1-6°dONLNdqêƒúÙ(ôƒ
  106. The Hierarv¿°dONLNd{êÙúB)0chical File System¿°dONLNdèêWúd)c1-7°dONLNdìùƒ©0(¶ƒIdentifying Files and Dir* °dONLNd¨ù1©R)mectories˝Ä°dONLNd∂ùf©s)51-9°dONLNd∫™∫∂Î(≥∫ Using Files≥†°dONLNd«™ˇ∂)E1-10°dONLNdÃ∑ƒ√ (¿ƒTµ¿°dONLNdÕ∑…√k)#esting for File Management Routines´@°dONLNdÚ∑Ä√ç)∑1-1rİdONLNdı∑ç√í)1°dONLNd˜ƒƒ–÷(ÕƒDefi†°dONLNd˚ƒ◊–?)ning a Document Recor+¿°dONLNdƒ?–E)hdGİdONLNdƒY–k)1-13°dONLNd—ƒ›œ(⁄ƒCr\°dONLNd—œ›) eating a New File…‡°dONLNd-—0›B)a1-14°dONLNd2fiƒÍ(ÁƒOpening a Filek`°dONLNdBfiÍ+)U1-15°dONLNdG΃˜(ÙƒReading File DataÖ`°dONLNdZÎ'˜9)c1-19°dONLNd_¯ƒŒ(ƒW¬†°dONLNd`¯Õ)    riting File DataR°dONLNdr¯$6)W1-21°dONLNdwƒ¸(ƒSaving a Fileÿ`°dONLNdÜ")L1-24°dONLNdãƒ2(ƒReverting to a Saved Fileí °dONLNd¶FX)Ç1-27°dONLNd´ƒ+((ƒClosing a File§@°dONLNdª+&)P1-29°dONLNd¿,ƒ8(5ƒOpening Files at  `°dONLNd—,8o)KApplication Startup Tfl°dONLNdÊ,n8~)_imee°dONLNdÎ,ì8•)%1-31°dONLNd9ƒEÚ(Bƒ
  107. Using a Prõ¿°dONLNd˙9ÚE).eferG‡°dONLNd˛9E-)
  108. ences File@°dONLNd
  109. 9BET)?1-33°dONLNdFƒR/(OƒAdjusting the File Menu'`°dONLNd(FDRV)Ä1-35°dONLNd-S∫_—(\∫Refer⁄ °dONLNd2S—_?)ence to File Managementa °dONLNdKST_f)É1-36°dONLNdP`ƒlÁ(iƒData Str``°dONLNdX`Ëlˇ)$ucturÊ@°dONLNd]`ˇl)esχ°dONLNda`l.)1-36°dONLNdfmŒy (vŒFile System Specifi@°dONLNdym!yW)S cation RecoräİdONLNdÖmWy])6d¶@°dONLNdàmqyÉ)1-36°dONLNdçzŒÜ(ÉŒStandar¥@°dONLNdîzÜA)"d File Reply Recorç °dONLNd¶zAÜK)Qds‡°dONLNd™z_Üq)1-37°dONLNdØáŒì5(êŒApplication Files Recorá°dONLNdΔá5ì?)gdsfl¿°dONLNd áSìe)1-38°dONLNdœîƒ†ˆ(ùƒ File Identifiv@°dONLNd‹î˜†;)3cation RoutinesİdONLNdÌîP†b)Y1-39°dONLNdÚ°ƒ≠÷(™ƒFile À °dONLNd˜°÷≠)Access Routinesc‡°dONLNd°2≠D)\1-40°dONLNdÆŒ∫(∑Œ
  110. Reading, Wû‡°dONLNdÆ∫j)3riting, and Closing FilesSİdONLNd2Æ∫ë)~1-40ˇ¨@ˇ ˇˇˇˇ@
  111. ˇ·ˇ‚7^
  112. 4*\˜, Palatino.+ú"CHAPTER œ´)\14⁄*˙¯,     Helvetica
  113. (‡*1 )-c)2    )iContents*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)10/15/91(¯ú Second line.4^*¿¯
  114. °dONLNd\∞h*(e∞Manipulating the File Mark©¿°dONLNd\>hP)é1-42°dONLNd!i∞u1(r∞Manipulating the End-of-File¨¿°dONLNd?iEuW)ï1-44°dONLNdDv¶ÇÓ(¶FSSpec Routinesx°dONLNdUvÇ)]1-45°dONLNdZÉ∞èÊ(å∞ Opening, Cr‡°dONLNdeÉÁèW)7eating, and Deleting FilesäİdONLNdÅÉkè})Ñ1-46°dONLNdÜê∞ú(ô∞Exchanging the Data in Tć°dONLNdûêúC)owo Files3‡°dONLNd®êXúj)91-49°dONLNd≠ù∞©ª(¶∞Cr\°dONLNdØùª©+) eating File System Specifi∑ °dONLNd…ù+©J)pcations÷°dONLNd“ù^©p)31-50°dONLNd◊™¶∂≠(≥¶Vú`°dONLNdÿ™¨∂ )olume ¿†°dONLNdfi™ ∂)Access RoutinesY`°dONLNdÔ™&∂8)\1-51°dONLNdÙ∑∞√‰(¿∞
  115. Updating Vå¿°dONLNd˛∑„√)3olumesÃ`°dONLNd∑√))41-51°dONLNd ƒ∞–∑(Õ∞O[‡°dONLNd ƒ∏–Ó) btaining a VD‡°dONLNdƒÌ–#)5 olume Refer!†°dONLNd#ƒ#–^)6 ence Number‰`°dONLNd0ƒr–Ñ)O1-52°dONLNd5—¶›:(⁄¶ Application Launch File Routines
  116. ‡°dONLNdW—O›a)©1-53°dONLNd\fiúÍ"(ÁúSummary of File Management¥@°dONLNdˇˇ)ö1-56ˇ'»@ˇ ˇˇˇˇ@
  117. ˇ·ˇ‚7^, Palatino.+ä"CHAPTER 
  118. 4⁄ä˙,     Helvetica    (‡ä About Files
  119. ‡(‡1ù)-‡)1(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.("È1    ˇˇ—ÚˇÆ°dONLNd8äC(@äIntroduction to File Managementˇˇˇˇˇˇ≠>(@1
  120. °dONLNd \ähº(eä This chapteg@°dONLNd+\Ωh”)3r intrõ°dONLNd1\”h&)oduces the data str√¿°dONLNdD\&h=)SucturI†°dONLNdI\>h`)es and r`°dONLNdQ\ah˛)#$outines your application can use to °dONLNduhät≤(qämanage f"İdONLNd}h≥tõ))6iles on Macintosh computers. It explains the basic strÒ‡°dONLNd≥hõt≤)Ëucturw¿°dONLNd∏h≥t¸)e of Macintosh fi˝°dONLNd…h¸t
  121. )Iles °dONLNdÕtäÄî(}äanQ`°dONLNdœtïĆ) d t/İdONLNd“t°Ä¶) h‡°dONLNd”tßÄ¥)e h‡°dONLNd÷t¥Ä»)ierarÖİdONLNd€t»ÄÍ)chical fidONLNd‰tÍÄ/)"le system (HFS)¯°dONLNdÛt/Äø)E used with Macintosh computersÿ¿°dONLNdt¿Äˇ)ë, and it shows °dONLNd Ääå(âähow you can use the services pr@°dONLNd?Äåx)çovided by the Standar…‡°dONLNdTÄxå)a d File Package, the File ManagerL`°dONLNdtÄå )è, °dONLNdvåäò∑(ïä
  122. the Finder@‡°dONLNdÄå∑ò,)-, and other system softwarA`°dONLNdöå,ò)ue components to crï@°dONLNd¨åò)Seate, open, update, and close fi} °dONLNdÃåò)àlesl °dONLNdœåò) .°dONLNd—ûä™ê(ßäY@İdONLNd“ûꙬ) ou should r@°dONLNd›û√™´)35ead this chapter if your application implements the c °dONLNdû¨™⁄)Èommands ◊¿°dONLNdû⁄™).
  123. typically °dONLNd$™ä∂™(≥äfound i¶°dONLNd+™™∂}) /n an application’s File menu—except for printinz¿°dONLNdZ™~∂Û)‘g commands and the Quit °dONLNdr∂ä¬√(øä
  124. command, wQ‡°dONLNd|∂ƒ¬‚):hich arí@°dONLNdÉ∂‚¬>)e described elsewher¶ °dONLNdó∂>¬B)\eo¿°dONLNdò∂C¬S). Tha‡°dONLNdú∂T¬z)    is chapteW°dONLNd•∂{¬≤)'r describes h‡°dONLNd≤∂≥¬Ã)8ow to,Zapf Dingbats°dONLNd∏Àä“è(—än
  125. °dONLNd∫»ñ‘û) crµ@°dONLNdº»û‘’) eate a new fi    †°dONLNd…»÷‘›)8le°dONLNdÛä‰è(„än
  126. °dONLNdŒ⁄ñÊÁ) open an existing fi솰dONLNd·⁄ÁÊÓ)Qle°dONLNd‰Ôäˆè(ıän
  127. °dONLNdÊÏñ¯ª)     close a fiaİdONLNdϺ¯√)&le°dONLNdÛäè(än
  128. °dONLNdı˛ñ
  129. ) save a document’s data i1†°dONLNd˛
  130. )mn aɰdONLNd˛
  131. ) fi¿°dONLNd˛
  132.  )    le°dONLNdäè(än
  133. °dONLNdñ) save a document’s data i1†°dONLNd0)mn aɰdONLNd3) fi¿°dONLNd6u)    le under a new name°dONLNdJ%ä,è(+än
  134. °dONLNdL"ñ.ô) rE°dONLNdM"ö.8)&evert to the last saved version of a fi°dONLNdt"9.@)üle°dONLNdw7ä>è(=än
  135. °dONLNdy4ñ@û) crµ@°dONLNd{4û@…)
  136. eate and r=°dONLNdÖ4 @Ì),ead a prÈİdONLNdç4Ì@˝)#eferdONLNdë4˛@)ences fi4@°dONLNdô4@&)!le°dONLNdúFäR‡(OäDepending on the rq‡°dONLNdÆF‡R˜)Vequirâ °dONLNd≥F˜R
  137. )>ements of your application, you may be able to accomplish all °dONLNdÒRä^ß([äyour fi  °dONLNd¯R®^∂)le-r÷°dONLNd¸R∂^\)(elated activities by following the instrF °dONLNd$R]^⁄)ßuctions given in this chapterú¿°dONLNdARŸ^˛)|
  138. . If your °dONLNdK^äj‚(gäapplication has morS¿°dONLNd^^‚j")Xe specialized fiA†°dONLNdn^#j÷)A'le management needs, you will need to ry†°dONLNdï^÷j)≥ ead some or °dONLNd°jäv∂(sä all of the r<İdONLNd≠j∑v°)-6emaining chapters in the Files section of this volume.°dONLNd‰|äàX(Öä/This chapter assumes that your application is r≈°dONLNd|Xà™)Œunning in an envir±Ä°dONLNd%|™à»)Ronmeng`°dONLNd*|…à˚) t in which tx@°dONLNd6|˚à)2he ˇˇAz.°dONLNd9àäîé(ëärR`°dONLNd:àéîÍ)outines that accept fiŒ°dONLNdPàÎî3)]le system specifiô¬°dONLNdaà3îT)Hcation r≠ú°dONLNdiàTîf)!ecor¸°dONLNdmàfîu)ds (,
  139. Courierˇ˝ƒn¡v°dONLNdqàuîô)FSSpecˇˇAz¡v°dONLNdwàôîû)$ r’P°dONLNdyàûî∞)ecorß∞°dONLNd}à∞î…)ds) arªä°dONLNdÉà…î)e available. File .°dONLNdïî䆫(ùäsystem specifiW@°dONLNd£î»†È)>cation r~ °dONLNd´îȆ˚)!ecorÚİdONLNdØî˚†)ds, intr `°dONLNd∑î†å) oduced in system softwarǰdONLNdœî冎)qe version 7.0, simplify the °dONLNdΆ䨩(©äidentifiV†°dONLNdÛ†™¨) cation of objects in the fi2‡°dONLNd†¨C)k le system.  `°dONLNd†C¨I).Y‡‡°dONLNd†H¨≠)our development envir•`°dONLNd/†Æ¨Ú)fonment may pr«‡°dONLNd<†Ú¨)Dovide °dONLNdB¨ä∏+(µä&“glue” that allows you to call those r“ °dONLNdh¨+∏∫)°!outines in earlier system softwar¢`°dONLNd⨪∏ )êe versions. If such °dONLNdù∏äƒ(¡ä8glue is not available and you want your application to r÷‡°dONLNd’∏ƒê)ıun i¿°dONLNdŸ∏ëƒù)n s¶ °dONLNd‹∏ùƒ€) ystem softwar7°dONLNdÈ∏‹ƒ)?
  140. e versionså`°dONLNdÛ∏ƒ
  141. ), °dONLNdÙƒä–Ó(Õäearlier than version 7.0} °dONLNd ƒÔ–.)e, you need to r °dONLNdƒ/–©)@ead the discussion of HFS fi°°dONLNd7ƒ©–Ú)zle-manipulation °dONLNdG–ä‹ç(ŸärE°dONLNdH–é‹Ã)outines in the €Ä°dONLNdW–Ë)>chapter “The Ÿ†°dONLNdd–‹>)< File Manage"İdONLNdo–?‹M)7r” i}İdONLNds–M‹å)n this volume.°dONLNdÇ‚äÓF(Îä+This chapter begins with a description of fi;†°dONLNdÆ‚GÓù)Ωles and how they arÁ °dONLNd¡‚ùÓ≠)Ve ork@°dONLNd≈‚ÆÓ)ganized into folders .°dONLNd⁄Óä˙t(˜ä5and volumes. Then it describes how to test for the prR`°dONLNdÓt˙Ø)Íesence of the R`°dONLNdÓØ˙”);FSSpecR`°dONLNd#Ó”˙Ÿ)$ r$¿°dONLNd%ÓŸ˙) outines and .°dONLNd1˙ä⁄(ähow to use those r8`°dONLNdC˙€F)Qoutines to perform the fi® °dONLNd\˙Ffl)k"le management tasks listed above. ˜†°dONLNd~˙flÔ)ôThe≥`°dONLNdÅ˙Ú) °dONLNdÇä≠(ächapter B`°dONLNd䯬)$ends6 °dONLNdé√≈) ∂ °dONLNdè≈)with descriptions of q°dONLNd§ Q)[ the data str
  142. İdONLNd∞Ri)2ucturê`°dONLNdµiã)es and rI °dONLNdΩå)#outines used to perform th °dONLNd◊)ve’†°dONLNdÿ)se °dONLNd€ä∏(ä tasks. The @°dONLNdÊπæ)/“@°dONLNdÁæ’)Refera`°dONLNdÏ’Ë)ence6@°dONLNdÈÓ)”6@°dONLNdÒÓ) and #`°dONLNdˆ    )“#`°dONLNd˜    4)Summaryî°dONLNd˛49)+”î°dONLNdˇ9a)
  143.  sections πİdONLNd        a¢)(in this chapter n¿°dONLNd    £´)Bar3¿°dONLNd    ¨Ò)    e subsets of the °dONLNd    ,ä*∏('ä
  144. equivalent>@°dONLNd    6π*·)/
  145.  sections c¿°dONLNd    @·*Ì)(for¿°dONLNd    CÓ*) the r¬ °dONLNd    I*Ó)6emaining chapters in the Files section of this volume.
  146. /HJ40HJ
  147. [Hc4\Hc \H\
  148. ˇ·ˇ‚7^ˇˇ£‰ˇÆ°dONLNd    ÄHHZû(VH About Filesˇˇˇˇˇˇ⁄|(V 1
  149. °dONLNd    åkäwê(täTµ¿°dONLNd    çkèw∫)
  150. o the userK†°dONLNd    ók∫wÃ)+, a fiÿ`°dONLNd    ùkÃwA)le is simply some data stor
  151. ‡°dONLNd    ∏kBwÇ)ved on a disk. TΩ °dONLNd    «kÅwfi)?o your application, a g‡°dONLNd    ›kflwÂ)^fiɆ°dONLNd    flkÂwÌ)le◊İdONLNd    ·kÌw) is a °dONLNd    ÁwäÉ∂(Ää    named, orE@°dONLNd    w∑É≈)-derÔ†°dONLNd    Ûw≈É3)ed sequence of bytes stor3¿°dONLNd
  152. w4É)o1ed on a Macintosh volume, divided into two forks °dONLNd
  153. =Éäè.(åä&(as described in the following sectionö†°dONLNd
  154. cÉ.è3)§, ö†°dONLNd
  155. eÉ3èh) “File Forks”İdONLNd
  156. qÉiè‘)6). The information in a fiô°dONLNd
  157. ãÉ‘è)kle can be used °dONLNd
  158. öèäõc(òä2for any of a variety of purposes. For example, a fiÅ °dONLNd
  159. Õècõ)Ÿ)le might contain the text of a letter or °dONLNd
  160. ˆõäß(§äthe numerical data in a spr£ °dONLNd õßp)veadsheet; these types of fić°dONLNd ,õqßà)qles ar¥‡°dONLNd 2õàß)e usually known as documents. °dONLNd Pßä≥ê(∞äT∫¿°dONLNd Qßè≥º) ypically a İdONLNd \ßΩ≥Í).document醰dONLNd dßÍ≥)- is a fi@¿°dONLNd lß≥Y)le that a user can cr@ °dONLNd ÅßY≥ı)U&eate that is associated with a single ˇñ÷@ˇ ˇˇˇˇ@
  161. ˇ·ˇ‚7^
  162. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  163. (‡*1 )-c)2    )9 About Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯
  164. °dONLNd\lhı(elYapplication, which the user expects to be able to open by double-clicking the document’s °dONLNdYhlt~* iconİdONLNd]ht∫) in the Finderö °dONLNdkhπtª):.°dONLNdmzlÜs(ÉlA∫†°dONLNdnzsÜ{) fiG`°dONLNdqz|Üæ)    Lle might also contain an application. In that case, the information in the fiËİdONLNdæzæÜÍ(Éæ le consists≥`°dONLNd…zÎÜÌ)- °dONLNd Ülíw(èlof …`°dONLNdÕÜwí5) -the executable code of the application itselfÏ`°dONLNd˙Ü5íJ)æ and ŸÄ°dONLNdˇÜKíØ)any application-specifi2‡°dONLNdÜ∞í∫)ec rË °dONLNdÜ∫í“)
  165. esour0`°dONLNdÜ”í‡)cesß@°dONLNd!܇íı) and °dONLNd&ílû(õldatafi °dONLNd*íûÑ). ¿°dONLNd,íÑû<)+Applications typically allow the user to cr/ °dONLNdWí=ûÍ)π$eate and manipulate documents. Some °dONLNd{ûl™¿(ßlapplications also crD°dONLNdèû¡™’)Ueate ô†°dONLNdîû’™Û)special„`°dONLNdõûÛ™˚) fip °dONLNdûû¸™Z)    les in which they stor놰dONLNd¥ûZ™t)^e userưdONLNd∫ût™ì)-specifip°dONLNd¬û)  c settings; qİdONLNdŒû¬™÷).such˜@°dONLNd“û÷™fi) fiѰdONLNd’ûfl™Ì)    les °dONLNdŸ™l∂t(≥larE°dONLNd€™u∂©)     e known as  °dONLNdÊ™©∂Ê)4preferences fi(†°dONLNdÙ™Á∂ˆ)>les.°dONLNd˘ºl»(≈lThe Macintosh Operating System ≤†°dONLNdº»)ñalso u‘†°dONLNdº»1)ses fi•°dONLNd$º2»ˆ).les for other purposes. For example, the File °dONLNdR»l‘‘(—lManager maintains the 6@°dONLNdh»’‘Ô)ihierarq@°dONLNdn»Ô‘)    chical orÆ`°dONLNdw»‘V)%ganization of fi?°dONLNdá»W‘—)Cles and folders on a volumeQ†°dONLNd¢»—‘”)z —†°dONLNd£»”‘ı)using a °dONLNd´‘l‡í(›l    special fiVİdONLNdµ‘ì‡])'.le located on that volume called the volume’s ı °dONLNd„‘]‡Ö)     catalog fi« °dONLNdÌ‘܇ê))le.õ°dONLNd‘뇪)
  166.  Similarly6@°dONLNd˙‘ª‡Ë)*, if virtual °dONLNd‡lÏK(Èl1memory is in operation, the Operating System stor °dONLNd8‡LÏÚ)‡$es unused pages of memory in a disk °dONLNd\Ïl¯r(ılfiå¿°dONLNd^Ïr¯©)le called the ¬Ä°dONLNdlÏ©¯Ô)7backing-store fièİdONLNd|Ï¯˙)Gle.°dONLNdIJl
  167. (l#No matter what its function, each fi“ °dONLNd§˛
  168. %)úle shar◊İdONLNd´˛%
  169. ‰)-es certain characteristics with every other fi‡°dONLNdŸ˛Â
  170. Ò)¿le. °dONLNd›
  171. l◊(lThis section describes th†°dONLNdˆ
  172. ÿ‹)leŸ@°dONLNd˜
  173. ‹é))se general characteristics of Macintosh fi
  174. ¿°dONLNd!
  175. è )≥les, including,Zapf Dingbats°dONLNd0l&q(%ln
  176. °dONLNd2x(~) fiå¿°dONLNd4~(û)le forks°dONLNd=1l8q(7ln
  177. °dONLNd?.x:~) fiå¿°dONLNdA.~: )"le size and access characteristics°dONLNddClJq(Iln
  178. °dONLNdf@xL~) fiå¿°dONLNdh@~L©)
  179. le system '‡°dONLNdr@™L≥),orb`°dONLNdt@≥L·)    
  180. ganization°dONLNdUl\q([ln
  181. °dONLNdÅRx^~) fiå¿°dONLNdÉR~^fl)le naming and identifip¿°dONLNdôR‡^˙)bcation
  182. É*â¯4Ñ*⯠Ñlѯ
  183. ˇ·ˇ‚7^ˇˇ◊ˇ◊°dONLNd†rlÉØ(l
  184. File Forksˇˇˇˇˇˇ®(1
  185. °dONLNd´âlï‚(ílMany operating systems tr¬`°dONLNdƒâ‚ïˇ)veat a fi€ °dONLNdÃâˇïj)le simply as a named, or`°dONLNd‰âkïy)lder¨¿°dONLNdÁâyï÷)ed sequence of bytes °dONLNd¸ïl°Õ(ûlQ(possibly terminated by a byte having a special value that indicates the end-of-fi„İdONLNdNïÕ°›(ûÕle). ã°dONLNdSï›°Î)As °dONLNdV°l≠ß(™lillustrated in ì¿°dONLNde°ß≠ø);FigurfİdONLNdj°ø≠”)e 1-1°dONLNdo°‘≠ˇ)    , however†°dONLNdx°ˇ≠Q)+, each Macintosh fié °dONLNdã°Q≠Ô)R$le has two forks, known as the data °dONLNdØ≠lπ®(∂lfork and the r⁄†°dONLNdΩ≠®π¿)<esour"‡°dONLNd¬≠¡π·)ce fork.
  186. ‹*̯4›*̯"›*_
  187. ˇ·ˇ‚7^    °dONLNdˇˇ(⁄l
  188. Figure 1-1°dONLNdÀ“Æ›()BThe two forks of a Macintosh fiÑ¿°dONLNdÍ“(›/)zle
  189. Ïl¨¯4Ìl¨¯
  190. Ìl¨º4ÏkÌlò*@P@PÌl-º◊
  191. ˆ˛ˇ¿Á
  192. ˆ˛ˇ‡Á
  193. ˆ˛ˇÁ
  194. ˆ˛ˇÁ
  195. ˆ˛ˇ¯Á
  196. ˆ˛ˇ¸Á
  197. ˆ˛ˇ˛Á
  198. ˆ˛ˇ˛Á
  199. ˆ˛ˇ˛Á
  200. ˆ˛ˇ˛Á
  201. ˆ˛ˇ˛Á
  202. ˆ˛ˇ˛Á
  203. ˆ˛ˇ˛Á
  204. ˆ˛ˇ˛Á
  205. ˆ˛ˇ˛Á
  206. ˆ˛ˇ˛Á
  207. ˆ˛ˇ˛Á
  208. ˆ˛ˇ˛Á
  209. ˆ˛ˇ˛Á˘˚ˇ˛˛ˇ¿Î˘˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛ˇ˛˛@΢˛˛ˇ˛˛@Î
  210. ˘˜@Î
  211. ˘˜@Î
  212. ˘˜@Î
  213. ˘˜@Î
  214. ˘˜@Î
  215. ˘˜@Î
  216. ˘|˜@Î ˘|¯¯Î
  217. ˘|˜Î
  218. ˘x˜Î
  219. ˘x˜Î
  220. ˘8˜‡Î
  221. ˘0˜`Î
  222. ˘0˜`ÎÓ@Î
  223. ˝˜˘ˇÓ˝1˙ˇ˛˘ˇÓ˝a˙ˇ˛˘ˇ¿Ô˝A˘ˇ̎¿Ô˝A˘ˇ̎¿Ô˝A˘ˇ̎¿Ô˝A˘ˇ̎√Ä˝A˘ˇ̎¬@˝A˘ˇ̎¬LÃúÃhÁı˝A˘ˇ̎√üÚô>T4Ĉ˝A˘ˇ̎¬Q≤ôT‘Ĉ˝A˘ˇ̎¬NÃxÓTwı˝A˘ˇ̎¿¸ıò*@ÄP@ÄP-llº˝A˘ˇ̎¿¸ı˝A˘ˇ̎¿¸ı˝A˘ˇ̎¿Ô˝A˘ˇ̎Ô˝A˘ˇ̎‹Ô˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ8A˘ˇ̎ƒ‡Ò$A˘ˇ̎ƒêÒ%flÄA˘ˇ̎ƒì3'30ı$hœ¡˘ˇ̎«Á¸¶O¯ı%´@A˘ˇ̎ƒîl¶Dhı8Ì¿A˘ˇ̎ƒì≥;∞ı˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔò*Ä¿PÄ¿Pll¨º˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝A˘ˇ̎ƒÔ˝a˘ˇ̎ÃÔ˝=˘ˇ̎¯Ô˝˘ˇÄ?˙ˇ¿Ô¸˙ˇÄ?˙ˇ¿Ô
  224. ¸˙ˇÄÂ◊◊◊◊˙0¸˝Ó˙ÿ0 ¸˝0Ó˙fløü‡˝wπÔ‹¿Ô˙€˜éflÄ˝ˇmÔ~=˜Ó˙flˇé€¿˝«ÌÔ0=ÁÄÔ˙Ûˇèõ‡˝8Ì˛7g¿Ô◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ò*¿ÍP¿ÍP¨l’º◊◊◊◊◊◊◊◊◊◊"˝ >`>p0Ɉ˝@ ¡Ä 4˘!˝"˛" HÇí˝†Pc˝å˘#˝ ˛ @@ÑÄ@e˘$˝8gkB8@@ÖÑ>I√Œ’釖•c˜{8@˙$˝H⁄)çH@@ÜöJ!e"Å ©$ñR"ùi†˙$˝@íQ@ÅÑ Aú‘!!FBÇ ≤E¢BIQ¿˙#˝A,ñ@ÑHA     #dB"ä§Eq"O9¥E2ö˘$˝·‹˙·¯Éâ"CÇâ89°Æ4œ$9“Ò¿˙¸"˛˝Ä˝˛˘¯¸"˛˛¸ ˛˘0¯¸˙¸˛˘ ¯◊#˝8√`¿Ä‡á¡∞`Å¿˛Ê@0˘#˝1IJ ˛Ñ@ÄÄIJ ¿ `˘'˝ 2Ä Ä@Ä †¸ˇ)˝%/  Rç1˚é=ÅÁÖ>ny=ÙpÁÜÑ£^4q4ƒ{Ä)˝#%%¥–TíK)NÄç%ö    d—)òàHÑåö$äI¶õZ)ˇ)˝#JD‡Y"ÇQ!$ÑNB""D°Q(ëPÑ    Hîâ'\Qˇ)˝#KJ_ë'ú⁄"ôPN%Øoô"Z-!ë†$I÷ú»$‡Zˇ)˝#Ús¨‡◊gíÈé1…ñÈ‹íI ‡é5Δ§i«$úíˇ ÛÌ ¸fi ¸fi¿¸◊˝:¸ÄÁ˝ D¸Ê˝(Ñ˛ Ê˝ (Û»AÌ3Õq4x¿Ë˝ HI)°—%&ò) Ë˝ |ä1¡í*'RÁ˝ ÑíZ)2R» Z`˲üeë¿·…%üG!ëÑËòÅP@PHHE˛¥íIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  225. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@PÌl-º'Åű¢ÊˇÅ´¢ˇÛˇ¯ˇˇÅ¨¢ˇÛˇ¯ˇˇÅ≠ ¢ˇÈˇÅ™¢ˇÛˇ¯ˇÅ™¢ˇÛˇ¯ˇÅ™ ¢ˇÈ˙ˇÅ∞¢ˇÛˇÚˇÅ∞¢ˇÛˇÚˇÅ∞ ¢ˇ„ˇÅ∞¢ˇÛˇÚˇÅ∞¢ˇÛˇÚˇÅ∞ ¢ˇ„ˇÅ∞¢ˇÛˇÚˇÅ∞¢ˇÛˇÚˇÅ∞ ¢ˇ„ˇÅ∞¢ˇÛˇÚˇÅ∞¢ˇÛˇÚˇÅ∞ ¢ˇ„ˇÅ∞æ‰ˇÛˇÚˇÁˇÅÀæˇÊˇÛˇÚˇÁˇÅÀæˇÊˇ„ˇÁˇÅÀæˇÊˇÛˇÚˇÁˇÅÀæˇÊˇÛˇÚˇÁˇÅÀæˇÊˇ„ˇÁˇÅÀæˇÊˇÛˇÚˇÁˇÅÀæˇÊˇÛˇÚˇÁˇÅÀæˇÊˇ„ˇÁˇÅÀæˇÊˇÛˇÚˇÁˇÅÀæˇÊˇÛˇÚˇÁˇÅÀæˇÊˇ„ˇÁˇÅÀæˇÊˇÛˇÚˇÁˇÅÀæˇÊˇÛˇÚˇÁˇÅÀæˇÊ·ˇÁˇÅÀæˇÂ‚ˇÁˇÅÀ æˇ¨ˇÅÀ æˇ¨ˇÅÀ æˇ¨ˇÅÀ æˇ¨ˇÅÀ æˇ¨ˇÅÀ æˇ¨ˇÅÀ ¿¸ˇÆˇÅÀ ¿¸ˇ∞˚ˇÅŒ ¿¸ˇØ˝ˇÅÕ ¿˝ˇÆ˝ˇÅÕ ¿˝ˇÆ˝ˇÅÕ ø˛ˇÆ˛ˇÅÃøˇˇ¨ˇˇÅÃøˇˇ¨ˇˇÅÃ
  226. ÅˡÅÀ fi˛ˇØ¡ˇÅÈflˇˇ˛¡ˇˇ√ˇÅȇˇˇ˝ˇ√ˇˇ√˛ˇÅ·ˇ¸ˇ√˛ˇÚˇ√˛ˇÅ·ˇ¸ˇ√˛ˇÚˇ√˛ˇÅ·ˇ¸ˇ√˛ˇÚˇ√˛ˇÅ·ˇ¸ˇ√˛ˇÚˇ√˛ˇ˝˛ˇÅÚ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˝ˇˇÅÛI‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˝ˇˇˇˇˇˇˇˇˇ˛ˇˇˇˇˇ˛ˇˇˇ˛˛ˇ˛ˇ°B‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˝˛ˇ¯ˇˇˇˇˇˇ¸ˇˇˇˇ˝ˇˇˇˇ¢J‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˝ˇˇˇ˛ˇˇˇˇˇˇˇˇˇ˛ˇ¸ˇˇˇˇˇˇˇˇ¢E‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˝ˇˇ˛ˇˇˇˇˇ˛˝ˇ˛˛ˇ˛ˇˇˇˇ˛˛ˇ˛ˇ°‡ˇ¸ˇ√˛ˇÚˇ√˛ˇŒˇüòÅP@ÄPHHE˛∞ìIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  227. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@ÄP-llº'‡ˇ¸ˇ√˛ˇÚˇ√˛ˇŒˇü‡ˇ¸ˇ√˛ˇÚˇ√˛ˇŒˇü‡ˇ¸ˇ√˛ˇÚˇ√˛ˇÅ·ˇ¸ˇ√˛ˇÚΩˇÅ̇ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚøˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚøˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚøˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ(˜˛ˇ˙ˇıˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇ˜˛ˇÅ¸.˜ˇˇ˚ˇıˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇ˜ˇˇÅ˝O˜ˇˇ˛ˇ˚ˇ˘ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇ˜ˇˇˇˇˇˇˇˇˇ˛ˇ ˇˇˇˇˇˇùC˜ˇˇ˛ˇˇˇ˛ˇˇ˚ˇ¸ˇ√˛ˇÚøˇ˛˙ˇ˝˛ˇ¯ˇˇˇˇˇˇ¯ˇûU˜ˇˇˇˇˇˇˇˇˇ˙ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇ˜ˇˇˇ˛ˇˇˇˇˇˇˇˇˇ˛ˇ˛ˇˇˇûL˜˛ˇ˛˛ˇˇˇ˛ˇ˙ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇ˜ˇˇ˛ˇˇˇˇˇ˛˝ˇ˛˛ˇ˛ˇˇˇù‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚøˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚøˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔòÅPÄ¿PHHE˛¥îIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  228. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêêÄ¿Pll¨º'‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚøˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚøˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇ¸ˇ√˛ˇÚˇ√˛ˇ˛ˇÅÔ‡ˇˇ˝ˇ√˛ˇÚˇ√˛ˇˇˇÅÔfl˝ˇˇ√˛ˇÚºˇÅÓ ⁄øˇ¡ˇÅÎ ÿ¡ˇ¡ˇÅÎÿ¡ˇÅöÅűÅűÅűÅű%…˝ˇ˚ˇˇ¯ˇˇ˙ˇˇ÷˝ˇ›ˇˇ˘ˇˇÅË-…ˇˇˇˇ¸ˇˇ˘ˇˇ˘ˇˇ÷ˇˇˇˇflˇˇ¯ˇˇÅËA…ˇˇ˚ˇ˚ˇ˛˚ˇ˘ˇŸˇˇˇˇ˛ˇ˝ˇ˛ˇ˝ˇ˚ˇ˛ˇ˛˙ˇ¯ˇÅÎD…ˇˇˇˇ˚ˇ˝ˇ˛˛ˇˇˇ˚ˇ◊˝ˇ˘ˇˇˇˇˇ˝ˇ˝ˇ˚ˇ˛˝ˇ¸ˇ˛ˇÅÈC…ˇˇÛˇ˛˛ˇˇˇˇˇ˝ˇÿˇˇ˝ˇ˛˚ˇˇˇ˝ˇ˝ˇˇˇ˚˝ˇ˝ˇ˝ˇÅÍD…˝ˇˆˇ˛¸ˇˇˇ¸ˇŸˇˇˇˇ˙ˇ˛ˇ˛˛ˇˇˇ˘ˇ˛ˇˇ˛ˇˇˇ¸ˇÅÎÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűòÅP¿ÍPHHE˛∞ïIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  229. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê¿ÍP¨l’º'ÅűÅűÅűÅűÅűÅűÅűÅűÅűÅű\fl¸ˇˇˇÂˇ˚ˇ˛¸ˇ˛ˇ˜ˇ˛ˇˇ˝ˇ¸˚ˇˇˇflˇˆˇˇÓˇÙˇˇ¸ˇˇÙˇˇÌˇˇ¯ˇˇˇˇøcflˇ˛ˇ‚ˇˇ˚ˇ˛ˇ˛ˇ˛ˇ˜ˇˇˇˇ˛ˇ¸ˇˇˇˇ‡ˇˇˆˇÔˇˇÙˇˇ˛ˇˇ‹ˇ˘ˇˇ˛ˇˇøTflˇfiˇ˚ˇ˝ˇ˚ˇˆˇ˚ˇ˝ˇ˚ˇ˝ˇÙˇÌˇıˇÓˇÚˇˇˇˇÎˇÙˇ¯ˇ¸ˇæ∂fl˛ˇ˝ˇˇ˛ˇ    ˇˇˇˇˇˇ˝ˇ˙ˇ˚ˇ˝˛ˇ˝ˇˆˇ˚ˇ˝ˇ˚ˇ˝ˇˇˇ˝ˇ˝¸ˇˇˇ˛ˇ˝˝ˇ˛ˇ    ˇˇˇˇˇˇ˛˛ˇ˝˛ˇ˝ˇ¸ˇˇˇ˝ˇˇˇˇ˛ˇˇˇˇˇ˛˚ˇ˛ˇ˛˛ˇ˛˝ˇˇˇ˝˝ˇ˛ˇ˝ˇ√◊‡ˇˇ˛ˇˇˇˇˇ˛ˇˇˇˇ˛ˇˇˇ˚ˇ¸ˇ˝ˇˇ˝ˇˆˇ¸ˇ¸ˇ˚ˇ˝    ˇˇˇˇˇˇ˝ ˇˇˇˇˇ˛ˇ˝ˇ˛ˇ˛ˇˇˇˇˇ˛ˇˇ˛ˇ˛ˇˇ˚ˇˇ¸ˇˇˇˇˇˇˇˇˇˇˇˇˇ˛ˇ˛ˇˇ˛ˇˇ¸ˇ˛    ˇˇˇˇˇˇƒ≈‡ˇ˚ ˇˇˇˇˇ˛ˇ˝˛ˇ˙ˇ¸ˇ˝ˇ˚ˇ˚ˇˇ˝ˇ˝ˇ˚ˇ¸ˇ¸ˇˇ˛ˇ¸
  230. ˇˇˇˇˇˇ˝ˇ˝ˇˇ˝ˇˇ˛ˇˇ¸ˇ˝ˇ˝ˇˇ¸ˇ˛ˇ¸    ˇˇˇˇˇ˛ˇˇ¸ˇˇˇ˛ˇˇ˝    ˇˇˇˇ¸ˇ˛ˇˇ˛˛ˇ√Œ‡ˇ¸ˇˇˇˇˇˇˇˇ˝ˇ¯ˇ˚ˇ˝ˇ˚ˇ˝ˇ˚ˇ˝ˇˇ˝ˇ¸ˇ˝ˇˇˇ˙ˇ˛ˇˇˇˇˇ˛ˇ˝ˇ˛ˇ˛ˇˇ˛    ˇˇˇˇˇ˛ˇ˛ˇˇ˚ˇ˛ˇ˛ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇˇˇ˛ˇ˛    ˇˇˇˇˇ¸ˇ˛ˇˇˇˇ¿∂·˛ˇ˝˛ˇ˛ˇ¸ˇˇ¸˛ˇ¸˛ˇ¸ˇ˛˛ˇ˝˚ˇ˚˛ˇ˝ˇ˝ˇ¸˛ˇ˛ˇˇ˛˛ˇ˝ˇ˛ˇˇ˝˛ˇ¸ˇ˝˛ˇˇ˛ˇˇ˛ˇ¸˛ˇˇ˙ˇˇˇ˝ˇˇˇ˛ˇ˛    ˇˇˇˇˇ˝ˇˇˇ˝˛ˇ˛ˇˇˇ¸ˇ˛˝ˇ˛˛ˇ√◊ˇ˛ˇ‰ˇfiˇ‘ˇ·ˇΩˇ∂!◊ˇ˛ˇ„ˇ‡ˇ’ˇˇ‚ˇˇæˇˇµ÷˛ˇ¡ˇ‘ˇ·ˇΩˇ¥Åű\fl˛ˇˆˇˇ˝ˇˇ¯ˇˇ¸ˇˇÙˇˇÌˇˇ˘˝ˇÂˇˇ˝¸ˇ¸ˇˇˇˇ¸ˇˇÙˇ˚˛ˇ›¸ˇˇˇˇ¯ˇˇ¸ˇˇΩOfiˇÓˇ˜ˇˇ˛ˇˇ‹ˇ˙ˇ˛ˇ‰ˇ˝ˇ˛ˇ˚ˇÍˇ˙ˇ‹ˇ˛ˇ¸ˇˇ˜ˇˇ˛ˇˇºZflˇÓˇˆˇˇˇˇÎˇÙˇ˘ˇ˛ˇÂˇ¸ˇ¯ˇ¸ˇˇ˙ˇ˘ˇÒˇıˇ¯ˇˆˇˇˇˇÕˇÒÂflˇ˝ˇ˛˛ˇˇˇˇˇ˛ˇ˚ˇˇˇˇ˛ˇˇˇˇˇ˛˚ˇ˛ˇ˛˛ˇ˛˝ˇˇˇ˚ˇ˚ˇ˝ˇˇ˛˛ˇ˝ˇ˝ˇˇ¸˛ˇ¸ˇˇ¸ˇˇˇ˛ˇ˝ˇˇ˙ˇ˝ˇ¸ˇˇ˛˛ˇ˝˛ˇ˛ˇ˚˛ˇ˝ˇˇˇ˝ˇ¸ˇˇˇˇ˛ˇˇˇ˝ˇ˛ˇˇˇ˛˛ˇ˛
  231. ˇˇˇˇˇˇ˛ˇ˛˝ˇ˛ˇÚflˇˇˇˇˇˇˇˇˇˇˇˇˇ¸ˇˇˇˇˇˇˇˇˇˇˇˇˇ˛ˇ˛ˇˇ˛ˇˇ˙ˇ˛ ˇˇˇˇˇˇ˛ ˇˇˇˇˇˇ¸ˇˇ˛ˇˇˇˇˇˇˇˇˇ˛ˇˇˇˇ˙ˇ˛    ˇˇˇˇˇ˛ˇ˛ˇ˝ˇˇ˛ˇ˝ˇˇ˛
  232. ˇˇˇˇˇˇ˝ˇˇˇˇˇˇ˛"ˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇ˛ˇˇˇÒ‡ˇˇˇ˝ˇ˛ˇˇ˛ˇ˛ˇ˚    ˇˇˇˇˇ˛ˇˇ¸ˇˇˇ˛ˇˇ˝    ˇˇˇˇ˝ˇ˛ˇ˛ˇˇ˝ˇ˝ˇˇˇˇ˛ˇ¸ˇ¸ˇ˛ˇˇ˛ˇˇˇ˝ˇˇˇ˛ˇ˚ˇ˛ˇˇ˛ˇˇ˛ˇ˝ˇ˝ˇˇ˝ˇ˝ˇ˚ˇˇ˛˛ˇ¸    ˇˇˇˇˇ˛ˇˇˇˇ˛ˇˇˇ˛ˇ˛ˇˇˇ˛ˇ˛ˇˇ˛ˇÒ˚‡ˇˇˇˇˇˇˇˇ¸ˇ˘ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇˇˇ˛ˇ˛    ˇˇˇˇˇ¸ˇ˛ˇˇ¸ˇ˛ˇ˛    ˇˇˇˇˇ˝ˇ˝ˇ˝ˇˇ¸ˇ    ˇˇˇˇ˛ˇˇˇˇˇ˙ˇ˛ˇˇˇˇˇ˝ˇ˛ˇ˝ˇˇ˛ˇ¸ˇ¸ˇ˛ˇˇ˙ˇˇ˛ˇˇ˛ˇˇˇˇˇ˛ˇˇˇˇ¸ˇˇ˛ˇ˚ˇˇˇˇ˙·˝ˇˇ˛ˇ˛ˇˇˇˇ˛ˇ¸ˇˇˇ˛ˇ˛    ˇˇˇˇˇ˝ˇˇˇ˝˛ˇ˛ˇˇˇ˛ˇˇ˛ˇ˛˛ˇ˛ˇˇ˛˛ˇˇˇ˛ˇˇˇ˝˚ˇˇˇˇ˛ˇˇ˛ˇ˛ˇˇˇˇ˚˛ˇ
  233. ˇˇˇˇ¸˛ˇ¸ˇ˛˛ˇ¸˛ˇ˝˛ˇˇ˛˛ˇ˝ˇˇˇ˛ˇ˛ˇˇˇˇˇ˛ˇˇˇ˛ˇ˛˛ˇ
  234. ˇˇˇ˛ˇˇˇˇéˇÅ◊ˇ˛ˇ‘ÅÅ„ˇ˛ˇ‘
  235. ÅÅ‚˛ˇ”Åű›◊Ò◊ı˛◊◊“˛◊Å™fi◊◊Ú◊◊ˆ◊˛◊–◊Å©fl◊◊Ú◊ˆ◊˝◊Â◊Ó◊Å®Rfl◊◊˛˝◊˝◊◊˝◊¸◊˘˛◊
  236. ◊◊◊◊◊˝◊◊◊◊˛◊˛◊◊◊◊˘◊˝◊˛◊◊Å≥]‡◊◊˝◊◊◊◊◊◊◊◊˝◊˙◊˛◊◊◊◊◊◊˛◊◊◊◊◊◊◊◊◊◊¯◊˛◊◊◊◊Å¥S‡¸◊◊˛◊◊˛◊◊˛˛◊¸◊˚◊˝ ◊◊◊◊◊˛◊◊◊˛◊˛◊˛◊¯◊˛◊◊◊Å∞[·◊˝◊◊◊◊◊◊◊◊˘◊˛◊◊◊˛◊◊◊◊◊◊◊◊◊◊◊◊¸◊˜◊˛    ◊◊◊◊◊◊Å¥\‚◊◊¸◊ ◊◊◊◊◊◊˛˛◊˚˛◊˝˛◊◊◊◊◊◊◊¸◊◊˛˛◊◊˝◊˝˛◊◊◊˛◊◊˝◊Å∑ò*@P@P’lº˝˝ ˝˝‚ ˝é˝‚◊˝`«‡    PÈ„˝1Ö  [„˝ 2Å2í Á˝ RÅ5ßêíhˇFÛ¥Ë˝ TÅ jH¢êí))â$XË˝ YtâE$Pâ(PË˝ ëÜûU°6ñR»†Ë˝ ◊'tkÈ#§˚íG Ë◊◊◊◊˝<@˝Ä¿‰˝¿˝A ‰˝(ÄÇ ‰˝(ö?—ºÌ ‰˝(äJbIÑ ‰˝Q"DJÑ@‰˝Y•îÑÚ(Ñĉ˝Ò>‰ÉQ»„◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ò*@ÄP@ÄPlTº◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ò*Ä¿PÄ¿PTlîº◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ò*¿ÍP¿ÍPîlΩº◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊òÅP@PHHE˛¥ñIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  237. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@P’lº'⁄◊¸◊⁄◊Ë◊Ű⁄◊¸◊⁄◊Åဲ◊˛˛◊‹˛◊ÅàÅű-‡ˇˇ¸ˇˇ˛˚ˇ¯ˇˇ¯ˇˇ˘ˇ˛˛ˇˇˇÅë,flˇˇ˛ˇˇ˝ˇˇˇ¯ˇˇˇÌˇ˝ˇˇˇˇˇÅë0flˇˇˇˇ˚ˇ˜ˇˇˇÌˇ˝ˇˇˇÙˇÙˇÅ¨_‡ˇˇˇˇ˚ˇ˛ˇˇˇ˝ˇˇ˛
  238. ˇˇˇˇˇˇ˝ˇˇ˝ ˇˇˇˇˇˇ˛˘ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇÅ∑f‡ˇˇˇˇ˚ˇ˝ˇˇ˛ ˇˇˇˇˇˇ˛ˇˇ˛ˇˇˇ˝ˇˇˇ˛ˇˇˇˇˇˇˇ˛    ˇˇˇˇ˛ˇˇˇÅ∂a‡ˇˇˇˇ˚ˇ¸ˇ˝˛ˇˇˇ˛ˇˇˇ˛ˇˇ˛ˇ˛ˇˇˇ˛ˇˇ˝ˇ˛ˇˇ˛ˇ˛ˇˇˇ˝ˇˇÅµ`·ˇˇ˛ˇ˚ˇ˝ˇ˝ˇ˝ˇˇˇ˝ˇ ˇˇˇˇˇˇ˝ˇˇˇˇˇˇˇˇˇˇˇˇ˝ˇ˝ˇˇ˛ˇˇÅ¥^·ˇˇˇ˛ˇˇ˛ˇ˛ˇ¸˛ˇˇ˛ˇˇˇ¸ˇˇˇˇ˛˛ˇˇˇ¸ˇ˛ˇˇˇ¸ˇˇˇˇ˛˛ˇˇÅ¥ÅűÅűÅűÅűfl˝ˇ˛ˇ‘ˇˇ˙ˇˇÅìfi˛ˇˇˇ’ˇˇ¸ˇˇÅî"flˇˇ˛ˇÙˇÙˇÓˇ¸ˇ˛ˇÅî;flˇˇ˛ˇˇˇˇ˛˘ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇ˚ˇˇ¸ˇ˝ˇÅî@flˇˇ˛ˇ˛ˇˇˇˇˇˇˇ˛    ˇˇˇˇ˛ˇˇˇ¯ˇ˝ˇ˝ˇÅî>‡ˇˇ˛ˇ˛ˇˇ˝ˇ˛ˇˇ˛ˇ˛ˇˇˇ˝ˇˇ˜ˇ˝ˇ˛ˇÅì<‡ˇˇˇˇˇˇˇˇˇˇˇˇ˝ˇ˝ˇˇ˛ˇˇˆˇ˝ˇˇÅí8·˝ˇ˛ˇ¸ˇ˛ˇˇˇ¸ˇˇˇˇ˛˛ˇˇ˙˝ˇ˛ˇˇˇÅëÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűòÅP@ÄPHHE˛∞óIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  239. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@ÄPlTº'ÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűòÅPÄ¿PHHE˛¥òIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  240. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêêÄ¿PTlîº'ÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűòÅP¿ÍPHHE˛∞ôIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  241. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê¿ÍPîlΩº'ÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűÅűˇ(ê@ˇ ˇˇˇˇ@
  242. ˇ·ˇ‚7^
  243. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä About Files
  244. ‡(‡1ù)-‡)3(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿
  245. °dONLNd\ähë(eäA∫†°dONLNd\ëhô) fiG`°dONLNd\öh´)    le’s }†°dONLNd    \´hÁ)resource fork¬`°dONLNd\Áh*)< contains that fiïİdONLNd'\+h@)Dle’s rê¿°dONLNd-\@hX)esourŸ°dONLNd2\Xhä)ces. If the fiÏ`°dONLNd@\ähÚ)2le is an application, the °dONLNdZhätç(qärE°dONLNd[hét¶)esourç@°dONLNd`h¶t)Tce fork typically contains menu templates, dialog templates, fonts, icons, and even °dONLNd¥täÄM(}ä/the executable code of the application itself. D†°dONLNd„tMÄT)√A@°dONLNd‰tTÄø) particularly important r*`°dONLNd˝t¿Äÿ)lesourr†°dONLNdtÿÄ˝)
  246. ce is the ˇˇìÓ.°dONLNd Ääå»(âäapplication’s ,
  247. Courierˇ˛ª Ó°dONLNdÄ…åÌ)?'SIZE'ˇˇìÓÓ°dONLNd ÄÌåÚ)$ rz<°dONLNd"ÄÚå    )esourLú°dONLNd'Ä    å)=ce, which contains information about the capabilities of the .°dONLNddåäò‚(ïäapplication and its rÍ`°dONLNdyå‚ò3)Xun-time memory r°dONLNdâå4òK)Requir$@°dONLNdéåKòè)ements. If the fix¿°dONLNdüåèòÏ)Dle is a document, its r6‡°dONLNd∂åÌò)^esour °dONLNdªåò)ce °dONLNdæò䧢(°äfork typically contains pr醰dONLNdÿò˘§    )oefer:¿°dONLNd‹ò
  248. §˚)4ence settings, window locations, and document-specifi¿°dONLNdò˚§)Òc °dONLNd§ä∞¯(≠äfonts, icons, and so forth.°dONLNd/∂ä¬ë*A∫†°dONLNd0∂ë¬ô) fiG`°dONLNd3∂ö¬´)    le’s }†°dONLNd8∂´¬‘)    data forkfl`°dONLNdA∂‘¬)) contains the fi9¿°dONLNdQ∂¬)A?le’s data. It is simply a series of consecutive bytes of data. °dONLNdê¬äŒ>(Àä*In a sense, the data fork of a Macintosh fiP¿°dONLNdª¬?ŒZ)µle corr  °dONLNd¬¬[ŒØ)esponds to an entir\İdONLNd’¬ØŒº)Te fi≤‡°dONLNdŸ¬ºŒΔ)le ‰‡°dONLNd‹¬ΔŒ»)
  249. iÕ@°dONLNd›¬…Œ˛) n operating °dONLNdÈŒä⁄ (◊äsystems that tr†°dONLNd¯ŒÀ⁄Ë)Aeat a fi`°dONLNdŒË⁄∑)0le simply as a sequence of bytes. The bytes stor¯†°dONLNd0Œ∂⁄‹)Œ    ed in a fi$İdONLNd:Œ›⁄)'
  250. le’s data °dONLNdD⁄äÊE(„ä,fork do not have to exhibit any internal strm¿°dONLNdp⁄EÊ\)ªucturÛ†°dONLNdu⁄\Êø)e, unlike the bytes stor6@°dONLNdç⁄¿ÊÏ)d ed in the r˜¿°dONLNdò⁄ÏÊ),esour@°dONLNdù⁄Ê)ce °dONLNd†ÊäÚø(Ôä fork (which q`°dONLNd¨Ê¿Ú‚)6consists
  251. @°dONLNd¥Ê„ÚÂ)# ä@°dONLNdµÊÂÚ˜)of a S†°dONLNd∫ʯÚ˚)r†°dONLNdªÊ¸Ú)esour`‡°dONLNd¿ÊÚ)ce ¿°dONLNd√Ê Ú3) map‡°dONLNdΔÊ3Ú5) p‡°dONLNd«Ê6Ú])followedº‡°dONLNdœÊ]Ú_)' <‡°dONLNd–Ê`Úm)by ”†°dONLNd”ÊmÚp)rò†°dONLNd‘ÊqÚâ)esour‡‡°dONLNdŸÊâÚº) ces). Ratherl@°dONLNdÂÊºÚ )3, your application °dONLNd¯Úä˛ó(˚äis rÍ`°dONLNd¸Úó˛ˆ)esponsible for interpr‘İdONLNdÚˆ˛‰)_7eting the bytes in the data fork in whatever manner is °dONLNdI˛ä
  252. û(äapprI@°dONLNdM˛ü
  253. I)&opriate. The data fork of a document fiù°dONLNdt˛I
  254. )™+le might for example contain the text of a °dONLNdü
  255. ä†(äletterµ†°dONLNd•
  256. †•). °dONLNd®ä((%äEven though a Macintosh fi@ °dONLNd¬(y)zle always contains both a rC¿°dONLNd›y(ë)uesourå°dONLNd‚ë(ú)ce E‡°dONLNdÂù(±) fork °dONLNdÍ≤( )and a data fork, one °dONLNdˇ(ä4%(1ä#or both of those forks can be emptyB¿°dONLNd"(%4`)õ . Document fi+°dONLNd/(a4ˇ)<$les sometimes contain only data (in °dONLNdS4ä@—(=äwhich case the rk†°dONLNdc4—@È)Gesour≥‡°dONLNdh4È@J)ce fork is empty). MorS °dONLNd~4K@£)be often, document fiä@°dONLNdí4£@Î)Xles contain both °dONLNd£@äLç(IärE°dONLNd§@éL¶)esourç@°dONLNd©@¶L·)ces and data. Ò°dONLNd∑@·L);Application fi˚‡°dONLNd≈@L)=les generally contain r)`°dONLNd‹@ÄLò)besourq†°dONLNd·@òL)ces only (in which case, the °dONLNd˛LäX„(Uädata fork is empty). 5`°dONLNdL„X )YApplication fi@@°dONLNd!L Xi)=les can, however˝Ä°dONLNd1LhX¥)H, contain data too<@°dONLNdCLµX∑)M.°dONLNdE^äjî(gäW°dONLNdF^îj◊)
  257. hether you stor∞†°dONLNdU^◊jfi)Ce ˙@°dONLNdW^fij˙)specifih`°dONLNd^^˚jˇ)cÿ†°dONLNd_^ˇjâ)" data in the data fork or in the rª`°dONLNdÅ^âj°)äesour†°dONLNdÜ^¢j€)ce fork of a fi^¿°dONLNdï^€j)9 le depends °dONLNd†jävï(sälar-`°dONLNd£jñvZ) -gely on whether that data can usefully be strt@°dONLNd–jZvq)ƒuctur˙ °dONLNd’jqv~)ed _İdONLNdÿjvà)asúİdONLNd⁄jàvï)     a raİdONLNdfijñvÆ)esour©¿°dONLNd„jÆv)ce. For example, if the °dONLNd˚väÇË(ädata you want to storΔ`°dONLNdvËÇ)^Ae consists of a small number of names and telephone numbers, you °dONLNdQÇäéô(ãäcan¡†°dONLNdTÇôé»)  easily defi@°dONLNd`Ç…é·)0ne a rz@°dONLNdfÇ·é˘)esour¬Ä°dONLNdkǢéÌ)6ce type that pairs each name with its telephone numberî°dONLNd°ÇÌé )Ù. Then °dONLNd®éäö≥(óä    you can rí`°dONLNd±é≥ö    ))ead names and corr.@°dONLNd√é
  258. öl)Wesponding numbers fr(¿°dONLNd◊élöë)bom the r†°dONLNdfléëö©)%esour\‡°dONLNd‰é©ö∫)ce fi#İdONLNdÈéªöÌ) le by using °dONLNdıöä¶©(£äResourv@°dONLNd˚ö©¶‚) ce Manager r °dONLNdö„¶):
  259. outines. Tº@°dONLNdö¶)*o rv¿°dONLNdö¶p) etrieve the data stor †°dONLNd)öq¶ï)X    ed in a r¿°dONLNd2ö)#esour9°dONLNd7ö≠¶)ce, you simply specify °dONLNdN¶ä≤û(Øäthe r¢`°dONLNdS¶û≤∂)esour͆°dONLNdX¶∂≤e)&ce type and ID; you don’t need to know<‡°dONLNd~¶e≤)Ø', for instance, how many bytes of data °dONLNd•≤äæí(ªäarE°dONLNdß≤ìæ´)    e storHİdONLNd≠≤´æ€) ed in that rÇ¿°dONLNdπ≤€æÛ)0esourÀ°dONLNdæ≤Ûæ˛)ce.°dONLNd¬ƒä–Ò(ÕäIn some cases, however¿Ä°dONLNdÿƒÒ–î)g), it is not possible or advisable to stor(`°dONLNd    ƒï–ÿ)§e your data in rÕ@°dONLNd    ƒÿ–)CesourİdONLNd    ƒÒ–)ces. °dONLNd    –䋢(ŸäThe data might be too dif" °dONLNd    4–˙‹)pfi.‡°dONLNd    6–‹Ç) cult to put into the kind of str/İdONLNd    V–Ç‹ô)Çucturµ`°dONLNd    [–ô‹§)e rƒ°dONLNd    ^–§‹ª) equir€@°dONLNd    c–ª‹)ed by the Resour+°dONLNd    s–‹)Kce °dONLNd    v‹ä˱(ÂäManagerT†°dONLNd    }‹±Ë@)'$. For example, it is easiest to stor@ °dONLNd    °‹@Ë)è)e a document’s text, which is usually of °dONLNd     ËäÙÍ(Òävariable length, in a fi߆°dONLNd    ‚ËÍÙ∏)`/le’s data fork. Then you can use File Manager ro‡°dONLNd
  260. ËπÙ)œoutines to access °dONLNd
  261. #Ùä«(˝äany byte or gr?İdONLNd
  262. 1Ù»7)>oup of bytes individually‡°dONLNd
  263. JÙ79)o.°dONLNd
  264. Lä¢(äEven ]°dONLNd
  265. Q£ª)when `°dONLNd
  266. Uº) it is easy to defi0@°dONLNd
  267. h)Gne a rê@°dONLNd
  268. n3)esourÿİdONLNd
  269. s3)0ce type for your data, limitations on the Resour‡¿°dONLNd
  270. £)–ce °dONLNd
  271. ¶ä#(ä Manager might compel you to stor‹†°dONLNd
  272. Δ#√)ô&e your data in the data fork instead. É@°dONLNd
  273. Ï√ )†AΩ‡°dONLNd
  274. Ì –) r‡°dONLNd
  275. Ô—È)esourK °dONLNd
  276. ÙÈ    )ce fork °dONLNd
  277. ¸ä*('ä can contain at most about 2700 rã¿°dONLNd *0)éesour‘°dONLNd !0*U)ces. Mor˙†°dONLNd )U*ë)%e importantly¿°dONLNd 6ë*≈)< , the Resourp`°dONLNd B≈*)4ce Manager uses °dONLNd R*ä6ø(3äa linear sear™°dONLNd _*ø6)5ch when looking thr≥ °dONLNd r*6>)Yough a fiù°dONLNd {*?6T)'le’s rò@°dONLNd Å*T6l)esour‡Ä°dONLNd Ü*l6©)ce types and r&¿°dONLNd î*™6¬)>esouro°dONLNd ô*¬6˚)ce IDs. If the °dONLNd ®6äBH(?ä+number of types or IDs that need to be sear °dONLNd ”6IBv)ø ched is lar˘‡°dONLNd fi6uBƒ),ge, accessing the rb°dONLNd Ò6≈B›)Pesour™@°dONLNd ˆ6›B) ce data can °dONLNd BäN√(Kä become slow€Ä°dONLNd B¬N«)8. } °dONLNd B«N‡)As a r`°dONLNd B·N)>ule of thumb, if you need to manage data that would occupy mor‡@°dONLNd SBN(Ke °dONLNd UNäZ—(Wäthan about 500 r¿°dONLNd eN—ZÈ)Gesour9°dONLNd jNÍZ∂)0ces total, you should use the data fork instead.ˇÃ@ˇ ˇˇˇˇ@
  278. ˇ·ˇ‚7^
  279. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  280. (‡*1 )-c)4    )9 About Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯
  281. ^*j¯4^*j¯°dONLNdˇˇ(elIMPORTİdONLNdˇˇ)ANT
  282. ˇ·ˇ‚7^
  283. °dONLNdgls„(plIn general, you should storS`°dONLNdg„s)w    e data cr∞`°dONLNd$gsn)%eated by the user in a fi\¿°dONLNd=gosñ)g
  284. le’s data °dONLNdGslÜ(|l@fork, unless the data is guaranteed to occupy a small number of °dONLNdálão* rE°dONLNdàpãà)esourç@°dONLNdçàãÃ)ces. The Resour6 °dONLNdúÕãñ)E,ce Manager was not designed to be a general-°dONLNd»ãló‚(îlpurpose data storage and rJ†°dONLNd‚ã„ó*)wetrieval system. dONLNdÛã*ór)GAlso, the ResourJ`°dONLNdãsó~)Ice °dONLNdól£B(†l/Manager does not support multiple access to a fi± °dONLNd6óB£W)÷le’s r¨`°dONLNd<óW£o)esourÙ†°dONLNdAóo£õ) ce fork. If °dONLNdM£lØ¥(¨lyou want to storË@°dONLNd]£¥Øé)H3e data that can be accessed by multiple users of a °dONLNdêØlª(∏lsharS`°dONLNdîØª˝)ed volume, use the data forkv°dONLNd∞Ø˝ªˇ)~.,Zapf Dingbatsˆ°dONLNdˇˇ)u
  285. °dONLNdø¡lÕr( lBõ¿°dONLNd«¡rÕ¡)ecause the Resour∑°dONLNdÿ¡¡Õx)O+ce Manager is of limited use in storing larÀ¿°dONLNd¡xÕÃ)∑ge amounts of user‚°dONLNd¡ÃÕœ)T-°dONLNdÕlŸ$(÷l*generated data, most of the techniques in √‡°dONLNd@Õ$Ÿ_)∏“Using Files”˜Ä°dONLNdMÕ_Ÿ—); show how to use the File °dONLNdgŸlÂ(‚l"Manager to manage information stor=@°dONLNdâŸÂ5)£    ed in a fii °dONLNdìŸ5Â∂)& le’s data fork. See the section ·Ä°dONLNd≥Ÿ∂Âfl)Å    “Using a °dONLNdºÂlÒu(ÓlPrN†°dONLNdæÂvÒÜ)
  286. efer˙¿°dONLNd¬ÂÜÒµ) ences File”∂ °dONLNdÕÂ∂Ò’)0 for an √İdONLNd’Â’Ò˙)example=‡°dONLNd‹Â˚Ò˝)& Ω‡°dONLNd›Â˝Ò5)of the use of ;¿°dONLNdÎÂ6Òe)9
  287. the Resourè`°dONLNdıÂeÒÍ)/ce Manager to access data storœ@°dONLNdÂÍÒ˜)Öed °dONLNdÒl˝Ñ(˙lin a fiFİdONLNdÒÖ˝ö)le’s rA¿°dONLNd#Òö˝≤)esourä°dONLNd(Ò≤˝“)ce fork.
  288. #*)¯4#*(¯ #l#¯
  289. ˇ·ˇ‚7^ˇˇ◊ˇ◊°dONLNd1l"•(l    File Sizeˇˇˇˇˇˇ®(1
  290. °dONLNd;(l4´(1lThe size of a fi‡°dONLNdK(¨4¨)@>le is usually limited only by the size of the volume it’s on. @‡°dONLNdâ(¨4≥(1¨A{İdONLNdä(≥4µ) ˚İdONLNdã(µ4◊)volumem°dONLNdë(ÿ4Î)# is a °dONLNdó4l@d(=l:portion of a storage device that is formatted to contain fi‡°dONLNd“4e@u)˘les. ëİdONLNd◊4u@|)Aà°dONLNdÿ4|@„) volume can be an entir‰°dONLNdÔ4„@Í)ge °dONLNdÒ@lLÍ(Ildisk or only a part of a disk. i °dONLNd@ÍLÒ)~A£¿°dONLNd@ÒL)  3.5-inch fl¿°dONLNd@LÓ).0oppy disk, for instance, is always formatted as °dONLNdMLlX>(Ul,one volume. Other memory devices such as harí °dONLNdyL>Xy)“d disks and fi5°dONLNdáLzX€)<le servers can contain °dONLNdûXldº(almultiple volumes.
  291. r*~¯4r*~¯°dONLNdˇˇ*NOTE
  292. ˇ·ˇ‚7^
  293. °dONLNd∞|làë* ActuallyE °dONLNd∏|ëà£)%, a fi—‡°dONLNdæ|£à8)!le on an HFS volume can be as lar‚İdONLNdfl|8àü)ïge as 2 GB ($7FFFFFFF °dONLNdıàlî’(ëlbytes). Most volumes arH†°dONLNd à÷î˙)j    e not larH‡°dONLNdà˙îZ)$ge enough to hold a fi©`°dONLNd+àZîç)`le that size. B °dONLNd9àéîû)4An °dONLNd<îl†€(ùlHFS volume can be as larF`°dONLNdT')pge as 262,144 GB.°dONLNdˇˇ)Ou
  294. °dONLNdi¶l≤r(ØlT†¿°dONLNd{¶r≤Ì)he size of a volume varies fr=¿°dONLNdò¶Ó≤)| om one type of device to anotherΩ†°dONLNd∏¶~≤ä)ê. V⁄°dONLNdª¶â≤¥)     olumes ar^†°dONLNdƒ¶µ≤Í), e formatted °dONLNd–≤læœ(ªlinto chunks known as @°dONLNdÂ≤–æ)dlogical blocks`°dONLNdÛ≤æ*)?, each £†°dONLNd˙≤*æd)of which can ŰdONLNd≤eæœ);contain up to 512 bytes. ˆ¿°dONLNd ≤œæ÷)jA1`°dONLNd!≤◊æŸ) °dONLNd"æl ‘(«ldouble-sided 3.5-inch fl®`°dONLNd:æ‘ Ó)hBoppy disk, for instance, usually has 1600 logical blocks, or 800 K5İdONLNd|æÔ ı(«ÔBQ@°dONLNd}æı ˜).°dONLNd–l‹ó(Ÿl    GenerallyºÄ°dONLNdà–ñ‹¡)*    , however… °dONLNdë–¡‹ô)+5, the size of a logical block on a volume is of inter[°dONLNdΔ–ö‹Ô)Ÿest only to the disk °dONLNd€‹l˶(Âldevice driverI¿°dONLNdË‹¶Ë∫):@. This is because the File Manager always allocates space to a fi∑`°dONLNd)‹∫ËË(Â∫ le in units °dONLNd5ËlÙ◊(Òlcalled allocation blocks. í°dONLNdOË◊ÙÁ)kAn ™†°dONLNdRËÁÙ0)allocation blockØ °dONLNdbË0ÙM)I is a gr®†°dONLNdjËMÙˆ)'oup of consecutive logical blocks. The °dONLNdëÙlfi(˝lQFile Manager can access a maximum of 65,535 allocation blocks on any volume. For °dONLNd‚l * #small volumes, such as volumes on fl√‡°dONLNd „)§0oppy disks, the File Manager uses an allocation °dONLNd6 lÔ(l block size of 1 logical block. T‡°dONLNdV ÓO)Ço support volumes laraİdONLNdk P®)bger than about 32 MM‡°dONLNd~ ©Ø)YBi†°dONLNd Ø◊) , the File °dONLNdäl$≈(!lRManager needs to use an allocation block size that is at least 2 logical blocks. T◊@°dONLNd‹ƒ$Ò(!ƒ
  295. o support °dONLNdÊ$l0†(-l volumes larì@°dONLNdÒ$†0¯)4ger than about 64 M†°dONLNd    $˘0ˇ)YBõ`°dONLNd    $ˇ0Û)9, the File Manager needs to use an allocation block that °dONLNd    >0l<(9l,is at least 3 allocation blocks. In this wayİdONLNd    j0<:)≤, by prt`°dONLNd    q0:<H)ogr>°dONLNd    t0I<)essively incr¿`°dONLNd    Å0<fi)6easing the number of °dONLNd    ñ<lHô(ElFlogical blocks in an allocation block, the File Manager can handle lar``°dONLNd    ‹<ôH…(Eô ger and larF@°dONLNd    Á<…HŸ)0ger °dONLNd    ÎHlTñ(Ql    volumes. e‡°dONLNd    ÙHóTØ)+Figur8†°dONLNd    ˘HØT√)e 1-2÷ °dONLNd    ˛H√TP)" illustrates how logical blocks arÑ °dONLNd
  296.  HQTa)ée gr!‡°dONLNd
  297. $HbT·)ouped into allocation blocks.A†°dONLNd
  298. AH·T„) ˇõ@@ˇ ˇˇˇˇ@
  299. ˇ·ˇ‚7^
  300. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä About Files
  301. ‡(‡1ù)-‡)5(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿
  302. gHw4gHw"gH_
  303. ˇ·ˇ‚7^    °dONLNdˇˇ(dä
  304. Figure 1-2°dONLNd\ÃgZ)B$Logical blocks and allocation blocks
  305. °dONLNd%Qä]Í(ZäOThe size of the allocation blocks on a volume is determined when the volume is °dONLNdt]äi* Zinitialized and depends on the number of logical blocks it contains. In general, the Disk °dONLNdŒiäu˘* XInitialization Package uses the smallest allocation block size that will allow the File °dONLNd&uäÅ‘* Manager to addrΔ`°dONLNd5u‘Å)Jess the entirr °dONLNdBu    Å6)5
  306. e volume. @°dONLNdLu7Å>).A@‡°dONLNdMu>Åy)  non-empty fi+°dONLNdZuzÅ)<!le fork always occupies at least °dONLNd{Åäçõ(ää=one allocation block, no matter how many bytes of data that fiµ‡°dONLNdπÅõç(äõle fork contains. On a 40PİdONLNd“Åç    )k-°dONLNd”çäôì(ñäMı@°dONLNd‘çìôô)    B°dONLNd’çöô
  307. ) volume, for example, a fi}°dONLNdÔç
  308. ô
  309. )p@le’s data fork occupies at least 1024 bytes (that is, 2 logical °dONLNd/ôä•(¢ä#blocks), even if it contains only 1    †°dONLNdRô•y)ê1 bytes of actual data.°dONLNdj´ä∑ê(¥äTµ¿°dONLNdk´è∑ë):o distinguish between the amount of space allocated to a fik¿°dONLNd¶´í∑(¥íle and the number of bytes of °dONLNdƒ∑ä√fi(¿äactual data in the fi$ °dONLNdŸ∑fl√1)Ule, two numbers ar◊`°dONLNdÎ∑1√ø)R"e used to describe the size of a fi„¿°dONLNd∑ø√fi)éle. The —İdONLNd∑fl√)     physical °dONLNd√䜱(Ãäend-of-fiÌ¿°dONLNd(√±œπ)'leA†°dONLNd*√∫œ3)     is the number of bytes curr凰dONLNdF√3œó)yently allocated to the fib°dONLNd_√òœ≈)ele; it’s 1 gró °dONLNdl√≈œ)-eater than the °dONLNd{œä€ó(ÿäAnumber of the last byte in its last allocation block (since the fi¶Ä°dONLNdΩœó€ (ÿórst byte is byte number 0). °dONLNdŸ€äÁ£(‰äAs a rI@°dONLNdfl€§Á)esult, the physical end-of-fit`°dONLNd¸€ÁQ)xle is always ◊@°dONLNd    €QÁ[)5an®†°dONLNd €\Á^)  (†°dONLNd €_Á)'exact multiple of the allocation block °dONLNd3ÁäÛ≥(ä
  310. size. The ™¿°dONLNd=Á≥Û˚))logical end-of-fi"†°dONLNdNÁ¸Û)IlevİdONLNdPÁÛ’)1 is the number of those allocated bytes that curr°dONLNdÅÁ÷Û)“ently contain °dONLNdèÛäˇ√(¸ädata; it’s 1 gra@°dONLNdûÛ√ˇå)9/eater than the number of the last byte in the fi±Ä°dONLNdŒÛåˇ˚)…le that contains data. For °dONLNdÈˇä (äZexample, on a volume having an allocation block size of two logical blocks (that is, 1024 °dONLNdC ä∑* bytes), a fi¿`°dONLNdO ∑‚)-
  311. le with 50≈İdONLNdY ‚Á)+8≈İdONLNdZ ÁÉ)% bytes of data has a logical end-of-fi=¿°dONLNdÄ Ñ£)ùle of 50π °dONLNdà £®)9π °dONLNdâ ® ) and a physical end-of-°dONLNd†ä#ê( äfiå¿°dONLNd¢ê#œ)le of 1024 (see ,@°dONLNd≤–#Ë)@Figurˇ°dONLNd∑Á#˚)e 1-3úİdONLNdº¸#)).
  312. wä:4wä9
  313. wä:‰4vâwäò,@Z@Zwä∑‰’’¯` Ŀʯ‡Ä¿Ê¯    ¸Ôüü√‹˝ÛÄ˯    ˇøfi˝„ˆ˝ˇ¿Ë¯ˇèfifl„ˆ˝˛Á¯    ˛ˇflΩ·ú›˚¿Ë’’’’’ÌÍ ˚?Ùˇ˝‡Î ˚?Ùˇ¸0Π@?Ûˇ%ÄÒ @?ÛˇU#n@$?ÛˇU3sõÄÚ$¶ì@$?ÛˇuLô¶@Ú$¶ç@$?Ûˇ çLi¶@Ú?w@$?Ûˇç3πö@Ú?ÛˇÏ8˛?ÛˇÏ ˚?ÛˇÏ:@?Ûˇ tÔ&@?ÛˇLÔ&c[?ÛˇLÕl:îÁÄ?Ûˇu3û&îVÄ?Ûˇ0M1Z:cÀ?Ûˇ tœ, ¸?Ûˇ`Î
  314. ˚?Ûˇ‡Î
  315. ˚?Ûˇ0Î
  316. ˚?ÛˇÎ ¸?ÛˇÎ ¸$?ÛˇÎ ¸?ÛˇÎ ¸?ÛˇÏ ¸ ?Ûˇ Ï ¸<?ÛˇÏ ˚ÛˇÏ ˚?ÛˇÏ ˚?ÛˇÏ ¸?ÛˇÎ ¸$?ÛˇÎ ¸?ÛˇÎ ¸ ?ÛˇÎ ¸$?Ûˇ0Î ¸?Ûˇ`Î
  317. ˚?Ûˇ¿Î
  318. ˚?ÛˇpÎ
  319. ˚?ÛˇÎ ¸?ÛˇÎ ¸?ÛˇÎ ¸(?ÛˇÎ ¸<?Ûˇ Ï ¸?ÛˇÏ ¸?ÛˇÏ ˚Ûˇ Ï ˚?ÛˇÏ ˚?ÛˇÏ ¸?ÛˇÎ ¸ ?ÛˇÎò,@ÄZ@ÄZ∑䈉 ¸8?ÛˇÎ ¸?Ûˇ0Î ¸$?Ûˇ Î ¸?Ûˇ‡Î
  320. ˚?Ûˇ‡Î
  321. ˚?Ûˇ0Î
  322. ˚?ÛˇÎ ¸?ÛˇÎ ¸ ?ÛˇÎ ¸8?ÛˇÎ ¸$?Ûˇ Ï ¸$?ÛˇÏ ¸?ÛˇÏ ˚?ÛˇÏ ˚?ÛˇÏ ˚?Ûˇ Ï ¸<?ÛˇÎ ¸?ÛˇÎ ¸?ÛˇÎ ¸?ÛˇÎ ¸?Ûˇ0Î ¸?Ûˇ`Î
  323. ˚?Ûˇ¿Î˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚Úˇ‡Î˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍò,Ä¿ZÄ¿Zˆä6‰˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ˚?ÛˇÍ
  324. ˚ÛˇÄÎ ¸?ÛˇÎ ¸$?ÛˇÎ ˝8?ÛˇÎ ˝%ò?ÛˇÎ ˝$ ?ÛˇÎ ˝$<?ÛˇÎ
  325. ˚?ÛˇÎ
  326. ˚?ÛˇÎ ˚?ÛˇX̸?Ûˇd̸?ÛˇÑÌ˝8?ÛˇòÌ˝%à?Ûˇ Ì˝$?Ûˇ<Ì ˝$?ÛˇÎ
  327. ˚?ÛˇÎ
  328. ˚?ÛˇÎ
  329. ˚?ÛˇÎ
  330. ˚?ÛˇÎ
  331. ˚?ÛˇÎ ¸8?ÛˇÎ ¸$?ÛˇÎ ¸$?ÛˇÎ ¸$?Ûˇ0Î
  332. ˚?Ûˇ Î
  333. ˚?Ûˇ‡Î˚?ÛˇÍ˚ÛˇÍ˚ÛˇÍ’’’’’’’’ò,¿fiZ¿fiZ6äS‰’’’’’’’’’’’’’’’’’’’’’’’’’&¸ |¿ |‡1Ä1`¿¡Ä ˚$¸D˛D@ IÄÄ˝(c˝`˚%¸@˛@ÄÇÄ˝
  334.  e@˚(¸"pŒ÷ÑpÄ`ÇÄÁLÚ?d$…í–•c{úuÇNMiÑ˝(¸"ë¥SêÄÑÅ-¥Jd⁄he¥íA ©$ñ)"ñÜQE6ö˝òÅZ@ZHHE˛êöIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  335. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@Zwä∑‰'ÅÅßÅÅß!¥ˇˇˇˇ¯ˇˇ¸ˇˇ˜ˇˇÚˇˇÅ©¥˚ˇÒˇˇ˜ˇˇÚˇˇÅ©1¥¯ˇ˛ˇ¸ˇ˚ˇ˙ˇ˝˝ˇ˛ˇ˚ˇ¸ˇ˛ˇÅ∏'¥ıˇ˘ˇ˝ˇ˚ˇ˝ˇ˛˚ˇˇˇ˚ˇˆˇÅπ&¥ıˇ˛˚ˇ˝ˇˇˇ˘ˇ˛˚ˇˇˇ˚ˇ˘ˇÅ∂1¥˜ˇ˜ˇ˚ˇ˝ˇ˝ˇ˝ˇˇ˛ˇˇˇ˛ˇ˚ˇ˝ˇÅπÅÅßÅÅßÅÅßÅÅßÅÅß
  336. Å⁄ˇÅœ œçˇ˝ˇÅ“œˇè‡ˇ˝ˇˇÅ”ô˜ˇˆˇ˜ˇÒˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÎˇˇˇÚˇˇÅõ˜ˇÎˇ¯ˇˇ¸ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÏˇˇˇˇÚˇÅˇT˜ˇ˛ˇˇ˛˝ˇˇˇ˛ˇˇ˘ˇˇ˝ˇ⁄‡·÷‡˛ˇ˛ˇÏˇˇˇˇˇˇˇˇ˛ˇ˛ˇˇˇ˛ˇà¶˜ˇˇˇˇˇˇˇˇˇˇˇ˘ˇˇ˝ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡‡·‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÏ˛ˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇâ¥˜ˇˇˇˇˇˇˇ˛ˇˇˇˇ˘ˇˇ˝ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˙¯ˇ˘ˇˇ˚˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇ˘ˇˇ˜ˇ˛    ˇˇˇˇˇˇ˛ˇˇˇˇˇˇˇˇˇâg˜˚ˇ˛˝ˇ˛ˇ˛ˇˇ˘ˇˇ˝ˇ⁄‡˙ˇˇ¸ˇˇ˙˝ˇ¸÷‡˛ˇ˛ˇ˙ˇˇ¯ˇ˛    ˇˇˇˇˇ˛ˇ˛ˇ ˇˇˇˇˇˇâ}ÏˇÏˇˇ¸ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˙˝ˇ˙ˇ˝˝ˇ¸˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇ˙ˇˇÅfi(Ô˛ˇ‰Ÿˇ˙ˇˇ˛˘ˇ˛˝ˇ¸”ˇ˛¸ˇ˛ˇˇÅfi(œˇ⁄‡˙ˇˇ˛¸ˇ˚˝ˇ¸÷‡˛ˇ˛ˇ˙ˇˇÅfiê˜˛ˇˇ˜ˇÈˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡‡˙ˇˇ˛˘ˇˇˇˇˇ˝‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇ˘ˇˇˆ˛ˇˇ¯ˇÅ˜}˜ˇˇˇ˜ˇÔˇ¸ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl·˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÏˇˇˇ¯ˇÅ˜J˜ˇˇˇˇˇ˛    ˇˇˇˇˇˇˇˆˇˇ¸ˇ⁄‡·÷‡˛ˇ˛ˇÏˇˇˇˇˇˇˇˇˇˇˇˇÅ˝í˜˛ˇ
  337. ˇˇˇˇ˛ˇ˝ˇˆˇ¸ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl·˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÏ˛ˇ    ˇˇˇˇ˛ˇ˝ˇÅ˛∏˜ ˇˇˇˇˇˇ˛ˇˇˇˇˇˆˇ¸ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇˇˇÏ
  338. ˇˇˇˇˇˇ˛ˇˇˇˇˇÅ˛@˜˛ˇˇˇˇ˛˝ˇˇˇˇıˇ¸ˇè‡˛ˇˇÎ˛ˇˇˇˇ˝ˇˇˇˇÅ˝Ñ’ˇ¸ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇˇˇÅ“œàˇÅ“œˇè‡˛ˇˇˇÅ”œˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÅ”h÷ˇˇ¸ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡‡·‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÅ”◊ˇˇ˝ˇ⁄‡·÷‡˛ˇ˛ˇÅ”o‘ˇ˝ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡‡˙¯ˇ˙˝ˇ¸‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÅ”|÷ˇˇ¸ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˙ˇˇ¸ˇˇ˙ˇˇˇˇ˝˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇ¯ˇÅ›)◊ˇ˙ˇ⁄‡˙˝ˇ˙ˇ˝˝ˇ¸÷‡˛ˇ˛ˇ˘ˇˇÅ›z◊˝ˇ˝ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˙ˇˇ˛˘ˇ˛ˇˇˇˇ˝˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇ¯ˇÅ›%–ÿˇ˙ˇˇ˛¸ˇ˚ˇˇˇˇ˝”ˇ˛¸ˇ¸ˇÅ›%œˇ⁄‡˙ˇˇ˛˘ˇ˛˝ˇ¸÷‡˛ˇ˛ˇ¯ˇÅ›gœˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡‡·‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇ¯ˇÅ›f÷ˇˇ¸ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl·˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÅ”◊ˇˇ˝ˇ⁄‡·÷‡˛ˇ˛ˇÅ”É‘ˇ˝ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÅ”Ö’ˇˇ˝ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÅ”◊ˇˇ˝ˇè‡˛ˇˇˇÅ”Ö÷ˇˇ¸ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇˇˇÅ“œâˇÅ—œˇè‡˛ˇ˛ˇÅ”œˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÅ”Ñ’ˇ¸ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÅ”÷ˇˇ¸ˇè‡˛ˇ˛ˇÅ”Ü◊ˇˇ¸ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÅ”à◊˝ˇ˝ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇ˘ˇˇÅ›’ˇ¸ˇè‡˛ˇ˛ˇ˙ˇˇÅfiá’ˇ¸ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇ˜ˇÅfi–䡲¸ˇ˝ˇˇÅ›œˇè‡˛ˇ˛ˇ˙ˇÅ€Ñœˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇ˙˝ˇÅfiÉ÷˛ˇ˝ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÅ”◊ˇ˙ˇ⁄‡·÷‡˛ˇ˛ˇÅ”òÅZ@ÄZHHE˛åõIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  339. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@ÄZ∑䈉'e◊˛ˇ¸ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl·˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÅ”p‘ˇ˝ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡‡˙¯ˇ˙˝ˇ¸‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇˇˇÅ”.◊ˇˇ˝ˇ⁄‡˙ˇˇ¸ˇˇ˚ˇˇˇˇ˝÷‡˛ˇˇÅ“q÷ˇˇ¸ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡‡˙˝ˇ˙ˇ˛ˇˇ˘‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˚ˇÅ“œŸˇ˙ˇˇ˛˘ˇˇˇ˘–ˇÅ“'œˇ⁄‡˙ˇˇ˛¸ˇ¸ˇˇˇˇ˝÷‡˛ˇˇˇÅ”nœˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˙ˇˇ˛˘ˇ˛˝ˇ¸˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÅ”g÷˛ˇ˝ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡‡·‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÅ”◊ˇ˙ˇ⁄‡·÷‡˛ˇ˛ˇÅ”g◊˛ˇ¸ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡‡·‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÅ”ã◊ˇˇ˝ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇ˘ˇˇÅ›◊ˇˇ˝ˇè‡˛ˇ˛ˇ˙ˇˇÅfià÷ˇˇ¸ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇ˜ˇÅfiœãˇ˛¸ˇ¸ˇˇÅfiœˇè‡˛ˇ˛ˇ˙ˇˇÅfiÖœˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇ˘ˇˇÅ›É◊˝ˇ˝ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÅ”‘ˇ˝ˇè‡˛ˇ˛ˇÅ”É’ˇ¸ˇ‡‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡˛ˇ˛ˇÅ”Ñ÷ˇ˚ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇ˛ˇÅ”÷ˇ˚ˇè‡˛ˇˇˇÅ”Ñ÷ˇ˚ˇfl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl˛‡fl‡˛ˇˇˇÅ“œâˇÅ— œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœÅÅßÅÅß–ˇˇè˛ˇÅœ–ˇˇéˇˇÅœÅÅß–ˇˇéˇˇÅœ–ˇˇè˛ˇÅœ –ˇˇÅÅ⁄ÅÅß–ˇˇè˛ˇÅœ–ˇˇéˇˇÅœÅÅßÅÅß œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœòÅZÄ¿ZHHE˛êúIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  340. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêêÄ¿Zˆä6‰' œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ œˇè˛ˇÅœ–âˇÅ–÷ˇˇ¸ˇè˙ˇÅ”◊ˇˇ˝ˇè˛ˇ˛ˇÅ”fl˛ˇ˘ˇ˝ˇè˛ˇ˛ˇÅ”fl
  341. ˇˇˇˇˇˇ¸ˇè˛ˇ˛ˇÅ”flˇˇ˝ˇ˙ˇè˛ˇ˛ˇÅ”flˇˇ˝˝ˇ˝ˇè˛ˇ˛ˇÅ”œˇè˛ˇ˛ˇÅ”œˇè˛ˇ˛ˇÅ”œˇè˛ˇ˛ˇÙˇˇˇÅ‰’ˇ¸ãˇ˛ˇÙˇˇˇÅÂ!÷ˇˇ¸ˇè˛ˇ˛ˇ˙˛ˇˇ˝ˇÅÂ%fl˛ˇ˙ˇ¸ˇè˛ˇ˛ˇ˙    ˇˇˇˇˇÅ‰)flˇˇˇˇ˛ˇ¸ˇè˛ˇ˛ˇ˙ˇˇˇˇÅ‚'flˇˇ˚ˇ¸ˇè˛ˇ˛¸ˇ˛ˇˇˇ˝ˇÅÂflˇˇ˚ˇ¸ˇè˛ˇ˛ˇÅ”œˇè˛ˇ˛ˇÅ”œˇè˛ˇ˛ˇÅ” œãˇ˛ˇÅ”œˇè˛ˇ˛ˇÅ”œˇè˛ˇ˛ˇÅ”◊˛ˇ¸ˇè˛ˇ˛ˇÅ”◊ˇˇ˝ˇè˛ˇ˛ˇÅ”◊ˇˇ˝ˇè˛ˇ˛ˇÅ”◊ˇˇ˝ˇè˛ˇˇˇÅ”œˇè˛ˇˇÅ“ œˇè˚ˇÅ“œãˇÅœÕçˇÅœÕçˇÅœÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßòÅZ¿fiZHHE˛åùIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  342. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê¿fiZ6äS‰'ÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßhÿ¸◊◊◊Á◊◊˙◊˛¸◊˛◊˜◊˝◊◊˛◊˘◊ı◊◊Ò◊◊◊˛◊◊◊˜◊◊¯◊◊Ë◊ı◊◊¸◊◊Ù◊◊Ï◊◊Ó◊“]ÿ◊˛◊‰◊◊˚◊˛◊˛◊˛◊˜◊◊˛◊◊◊˙◊◊‰◊◊˚◊◊Ù◊fi◊◊ı◊◊˛◊◊€◊Ô◊◊“Nÿ◊›◊¸◊˝◊˚◊ˆ◊˚◊˝◊¸◊◊‰◊˙◊Û◊›◊Û◊◊◊◊Í◊Ù◊Ó◊—‰ÿ˛◊˝◊◊˛◊    ◊◊◊◊◊◊˝◊˘◊¸◊˝˛◊˝◊ˆ◊˝◊◊¸◊¸◊◊˙˛◊˛◊◊◊◊˝◊◊˛˚◊◊◊◊¸◊◊˝◊◊◊◊◊◊◊◊◊¸˛◊˝◊˝◊◊◊˝◊◊◊◊˛◊◊◊◊◊˛◊◊˝◊˛◊˛◊˛˛◊◊◊◊¸◊◊˛◊◊◊◊◊◊◊◊◊◊˝◊²Ÿ◊◊˛◊◊◊◊◊˛◊◊◊◊˛◊◊◊˚◊¸◊˝◊◊˝◊ˆ◊˚◊˝◊˝◊◊˚◊◊◊◊◊◊◊◊◊˛◊◊◊◊◊◊◊◊◊◊◊◊◊◊˝◊◊◊◊◊◊◊◊◊◊◊˝◊˛◊◊¸◊◊¸◊◊◊◊◊◊◊◊◊◊˛◊◊◊◊˛
  343. ◊◊◊◊◊◊˝◊◊◊◊˛◊◊˛◊◊◊◊◊◊◊◊◊◊Êò,@Z@ZSäì‰(¸"Å$¢Åá¿â$åDúà)8¥!B ≤EQBDǰä$ú˝(¸"ÇY, ÅàBRLñô º2@ÿ"Çq"O9ZE)"“…†˝)˝#√πÙ<√9·„ûIdÈ‹X#∏êŰÆ4Œí9…üI˝˚D˛˛˛˚ÄÒ˚D˛˛˛0¸˚8˙˛Ä ¸’"¸ pÜ¡Ä x˛al p˝˘ê ¯!¸ c˝à˛!   ˝à0¯'¸ @eà˛AA@@ Ä (˚@ˇ*¸$^9î@•c˜{@Ü9·A¡Oõû@O}9¿·°(◊çM1‡ˇ*¸$JKi†©$ñR"ù#ID¶ÇFô4J@E&"!#&ÖI"íi¶÷ä@ˇ*¸$î"â¿≤E¢BIêÖHÇë(T@ä$B!Gí%"Iƒó@ˇ*¸$ñîæ"O9¥E2âk¬ÊHñÄãHD$AË    uß2    8ġ+˝%‰ÁY¡Æ4œ$9“"„årEáÂ∫w$Å“H8#ÉáGq©q…'$ġ
  344. Ú Ïà˚‹à˚‹p˚’¸t¸Â¸0à¸Â¸P˛@¸ QÁêÇ⁄gö‚hÒÄÁ¸ êíSB-¢JM0R@Á¸ ˘cÇ)$TN §Ê˝    $¥4Rd•ê@¥¿Á˝>À#Å√íK>éB#Á¸˝‰ ¸˝· ¸˝·’¸¡è¿†“‚¸c
  345. @∂‚¸ ed!$@ʸ •4$kO!$—˛çÁhÁ¸ ©‘ëE!$RSH∞Á¸ ≤Èä"H°"P†Á˝"!<´Bm,§'ë@Á˝ÆN Ë◊“GI˜$é@Á’’’’¸xĽĄ¸9Ä˝Ç@„¸Q@„¸Q4£y⁄@„¸Qîƒí,@„¸¢(Dàî(Ä„¸≥K)    ‰P    ‚˝‚}…£ê&‚’’’’’’’’’’’’’ò,@ÄZ@ÄZì䓉’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ò,Ä¿ZÄ¿Z“䉒’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ò,¿fiZ¿fiZä0‰’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’òÅZ@ZHHE˛êûIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  346. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@ZSäì‰'ÏŸ◊˚ ◊◊◊◊◊˛◊˝˛◊˚◊˚◊˝◊˚◊˚◊◊˝◊˚◊˝◊˝¸◊˚◊˛ ◊◊◊◊◊˛◊◊˛◊˛◊◊˛◊◊˛◊¸◊◊◊˛◊˛◊◊◊◊˝◊˝◊◊˝◊˛◊¸    ◊◊◊◊◊˛◊◊¸◊˛◊◊˛◊◊˝◊◊˛◊◊¸◊◊◊˝◊◊˛◊◊˛◊◊◊˛◊ÂÔŸ◊¸◊◊◊◊◊◊◊◊˝◊˘◊◊˝◊˝◊˚◊˝◊˚◊˙◊˝◊˛◊˝◊˝$◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊¸◊˝◊˝◊◊◊◊˚◊◊◊◊¸◊˛◊◊¸◊˛◊˛◊◊˛◊◊˝◊˛◊ ◊◊◊◊◊◊˛
  347. ◊◊◊◊◊˚◊◊◊˛◊◊◊◊◊◊◊◊◊◊◊‚‡⁄˛◊˝˛◊˛◊¸◊◊¸˛◊˝˝◊¸◊˛˛◊˝˚◊˚˛◊˝◊˝◊˛◊◊˝◊˛˛◊˝◊◊◊◊◊◊◊˛◊◊˛◊˛◊˛◊◊◊¸◊˛˛◊˛◊˛◊◊˙˛◊◊˚◊◊◊˝◊◊◊˛◊˛    ◊◊◊◊◊˛◊◊◊◊˛˛◊˛◊◊◊˚◊˝˛◊◊¸◊◊◊◊˛˛◊ –◊˛◊‰◊fi◊‚◊ı◊Œ◊Å"–◊˛◊„◊‡◊·◊˜◊◊œ◊◊Ŏœ˛◊¡◊·˛◊¯◊Œ◊ŞÅÅß\ÿ˛ˇˆˇˇ˝ˇˇ¯ˇˇ¸ˇˇÙˇˇÌˇˇˆ˝ˇÂˇˇ˝¸ˇ¸ˇˇˇˇ¸ˇˇÙˇ˚˛ˇ›¸ˇˇˇˇ¯ˇˇ¸ˇˇΩO◊ˇÓˇ˜ˇˇ˛ˇˇ‹ˇ˜ˇ˛ˇ‰ˇ˝ˇ˛ˇ˚ˇÍˇ˙ˇ‹ˇ˛ˇ¸ˇˇ˜ˇˇ˛ˇˇºZÿˇÓˇˆˇˇˇˇÎˇÙˇˆˇ˛ˇÂˇ¸ˇ¯ˇ¸ˇˇ˙ˇ˘ˇÒˇıˇ¯ˇˆˇˇˇˇÕˇÒÂÿˇ˝ˇ˛˛ˇˇˇˇˇ˛ˇ˚ˇˇˇˇ˛ˇˇˇˇˇ˛˚ˇ˛ˇ˛˛ˇ˛˝ˇˇˇ¯ˇ˚ˇ˝ˇˇ˛˛ˇ˝ˇ˝ˇˇ¸˛ˇ¸ˇˇ¸ˇˇˇ˛ˇ˝ˇˇ˙ˇ˝ˇ¸ˇˇ˛˛ˇ˝˛ˇ˛ˇ˚˛ˇ˝ˇˇˇ˝ˇ¸ˇˇˇˇ˛ˇˇˇ˝ˇ˛ˇˇˇ˛˛ˇ˛
  348. ˇˇˇˇˇˇ˛ˇ˛˝ˇ˛ˇÚÿˇˇˇˇˇˇˇˇˇˇˇˇˇ¸ˇˇˇˇˇˇˇˇˇˇˇˇˇ˛ˇ˛ˇˇ˛ˇˇ˜ˇ˛ ˇˇˇˇˇˇ˛ ˇˇˇˇˇˇ¸ˇˇ˛ˇˇˇˇˇˇˇˇˇ˛ˇˇˇˇ˙ˇ˛    ˇˇˇˇˇ˛ˇ˛ˇ˝ˇˇ˛ˇ˝ˇˇ˛
  349. ˇˇˇˇˇˇ˝ˇˇˇˇˇˇ˛"ˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇ˛ˇˇˇÒŸˇˇˇ˝ˇ˛ˇˇ˛ˇ˛ˇ˚    ˇˇˇˇˇ˛ˇˇ¸ˇˇˇ˛ˇˇ˝    ˇˇˇˇ˙ˇ˛ˇ˛ˇˇ˝ˇ˝ˇˇˇˇ˛ˇ¸ˇ¸ˇ˛ˇˇ˛ˇˇˇ˝ˇˇˇ˛ˇ˚ˇ˛ˇˇ˛ˇˇ˛ˇ˝ˇ˝ˇˇ˝ˇ˝ˇ˚ˇˇ˛˛ˇ¸    ˇˇˇˇˇ˛ˇˇˇˇ˛ˇˇˇ˛ˇ˛ˇˇˇ˛ˇ˛ˇˇ˛ˇÒ˚Ÿˇˇˇˇˇˇˇˇ¸ˇ˘ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇˇˇ˛ˇ˛    ˇˇˇˇˇ˘ˇ˛ˇˇ¸ˇ˛ˇ˛    ˇˇˇˇˇ˝ˇ˝ˇ˝ˇˇ¸ˇ    ˇˇˇˇ˛ˇˇˇˇˇ˙ˇ˛ˇˇˇˇˇ˝ˇ˛ˇ˝ˇˇ˛ˇ¸ˇ¸ˇ˛ˇˇ˙ˇˇ˛ˇˇ˛ˇˇˇˇˇ˛ˇˇˇˇ¸ˇˇ˛ˇ˚ˇˇˇˇ˝⁄˝ˇˇ˛ˇ˛ˇˇˇˇ˛ˇ¸ˇˇˇ˛ˇ˛    ˇˇˇˇˇ˝ˇˇˇ˝˛ˇ˛ˇˇˇ˛ˇ˛ˇ˛ˇ˛˛ˇ˛ˇˇ˛˛ˇˇˇ˛ˇˇˇ˝˚ˇˇˇˇ˛ˇˇ˛ˇ˛ˇˇˇˇ˚˛ˇ
  350. ˇˇˇˇ¸˛ˇ¸ˇ˛˛ˇ¸˛ˇ˝˛ˇˇ˛˛ˇ˝ˇˇˇ˛ˇ˛ˇˇˇˇˇ˛ˇˇˇ˛ˇ˛˛ˇ
  351. ˇˇˇ˛ˇˇˇˇáˇÅ‘ˇ˛ˇ‘ÅÅŸˇ˛ˇ‘
  352. ÅÅÿ˛ˇ”ÅÅß÷ˇÒˇı˛ˇˇ“˛ˇÅß◊ˇˇÚˇˇˆˇ˛ˇ–ˇÅ¶ÿˇˇÚˇˆˇ˝ˇÂˇÓˇÅ•Rÿˇˇ˛˝ˇ˝ˇˇ˝ˇ¸ˇ˘˛ˇ
  353. ˇˇˇˇˇ˝ˇˇˇˇ˛ˇ˛ˇˇˇˇ˘ˇ˝ˇ˛ˇˇÅ∞]Ÿˇˇ˝ˇˇˇˇˇˇˇˇ˝ˇ˙ˇ˛ˇˇˇˇˇˇ˛ˇˇˇˇˇˇˇˇˇˇ¯ˇ˛ˇˇˇˇÅ±SŸ¸ˇˇ˛ˇˇ˛ˇˇ˛˛ˇ¸ˇ˚ˇ˝ ˇˇˇˇˇ˛ˇˇˇ˛ˇ˛ˇ˛ˇ¯ˇ˛ˇˇˇÅ≠[⁄ˇ˝ˇˇˇˇˇˇˇˇ˘ˇ˛ˇˇˇ˛ˇˇˇˇˇˇˇˇˇˇˇˇ¸ˇ˜ˇ˛    ˇˇˇˇˇˇÅ±\€ˇˇ¸ˇ ˇˇˇˇˇˇ˛˛ˇ˚˛ˇ˝˛ˇˇˇˇˇˇˇ¸ˇˇ˛˛ˇˇ˝ˇ˝˛ˇˇˇ˛ˇˇ˝ˇÅ¥”ˇ¸ˇ⁄ˇËˇÅû”ˇ¸ˇ⁄ˇÅÑ‘˛ˇ˛˛ˇ‹˛ˇÅÖÅÅß-Ÿˇˇ¸ˇˇ˛˚ˇ¯ˇˇ¯ˇˇ˘ˇ˛˛ˇˇˇÅé,ÿˇˇ˛ˇˇ˝ˇˇˇ¯ˇˇˇÌˇ˝ˇˇˇˇˇÅé0ÿˇˇˇˇ˚ˇ˜ˇˇˇÌˇ˝ˇˇˇÙˇÙˇÅ©_Ÿˇˇˇˇ˚ˇ˛ˇˇˇ˝ˇˇ˛
  354. ˇˇˇˇˇˇ˝ˇˇ˝ ˇˇˇˇˇˇ˛˘ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇÅ¥fŸˇˇˇˇ˚ˇ˝ˇˇ˛ ˇˇˇˇˇˇ˛ˇˇ˛ˇˇˇ˝ˇˇˇ˛ˇˇˇˇˇˇˇ˛    ˇˇˇˇ˛ˇˇˇÅ≥aŸˇˇˇˇ˚ˇ¸ˇ˝˛ˇˇˇ˛ˇˇˇ˛ˇˇ˛ˇ˛ˇˇˇ˛ˇˇ˝ˇ˛ˇˇ˛ˇ˛ˇˇˇ˝ˇˇÅ≤`⁄ˇˇ˛ˇ˚ˇ˝ˇ˝ˇ˝ˇˇˇ˝ˇ ˇˇˇˇˇˇ˝ˇˇˇˇˇˇˇˇˇˇˇˇ˝ˇ˝ˇˇ˛ˇˇÅ±^⁄ˇˇˇ˛ˇˇ˛ˇ˛ˇ¸˛ˇˇ˛ˇˇˇ¸ˇˇˇˇ˛˛ˇˇˇ¸ˇ˛ˇˇˇ¸ˇˇˇˇ˛˛ˇˇÅ±ÅÅßÅÅßÅÅßÅÅßÿ˝ˇ˛ˇ‘ˇˇ˙ˇˇÅê◊˛ˇˇˇ’ˇˇ¸ˇˇÅë"ÿˇˇ˛ˇÙˇÙˇÓˇ¸ˇ˛ˇÅë;ÿˇˇ˛ˇˇˇˇ˛˘ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇ˚ˇˇ¸ˇ˝ˇÅë@ÿˇˇ˛ˇ˛ˇˇˇˇˇˇˇ˛    ˇˇˇˇ˛ˇˇˇ¯ˇ˝ˇ˝ˇÅë>Ÿˇˇ˛ˇ˛ˇˇ˝ˇ˛ˇˇ˛ˇ˛ˇˇˇ˝ˇˇ˜ˇ˝ˇ˛ˇÅê<Ÿˇˇˇˇˇˇˇˇˇˇˇˇ˝ˇ˝ˇˇ˛ˇˇˆˇ˝ˇˇÅè8⁄˝ˇ˛ˇ¸ˇ˛ˇˇˇ¸ˇˇˇˇ˛˛ˇˇ˙˝ˇ˛ˇˇˇÅéÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßòÅZ@ÄZHHE˛åüIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  355. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@ÄZì䓉'ÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßòÅZÄ¿ZHHE˛ê†Ä˛ˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  356. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêêÄ¿Z“ä‰'ÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßòÅZ¿fiZHHE˛å°Ä˛ˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  357. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê¿fiZä0‰'ÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅßÅÅߡïæ@ˇ ˇˇˇˇ@
  358. ˇ·ˇ‚7^
  359. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  360. (‡*1 )-c)6    )9 About Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯
  361. g*w¯4g*w¯"g*_
  362. ˇ·ˇ‚7^    °dONLNdˇˇ(dl
  363. Figure 1-3°dONLNd\Æg )BLogical and physical end-of-f0°dONLNd\!g))sile
  364. °dONLNd!&l2r(/lY@İdONLNd"&r2) ou can move the logical end-of-fix °dONLNdC&2{)ële to adjust the size of the fi⁄‡°dONLNdb&{2Ù)xle. When the logical end-of-°dONLNd~2l>r(;lfiå¿°dONLNdÄ2r>Ú)le is moved to a position mor@°dONLNdù2Û>≤)Å-e than one allocation block short of the curri °dONLNd 2≤>È)øent physical °dONLNd◊>lJí(Glend-of-fi¥†°dONLNd‡>íJ⁄)&Kle, the File Manager automatically deletes the unneeded allocation block fr/@°dONLNd+>€JÎ(G€om °dONLNd.JlVÇ(Slthe fiÍ °dONLNd4JÇV∂)le. Similarly∑`°dONLNdAJ∂VÒ)4, you can incrÛ¿°dONLNdOJÒVB);ease the size of a fiÊİdONLNddJCV’)R!le by moving the logical end-of-fi߇°dONLNdÜJ÷Vı)ìle past °dONLNdéVlb…(_lthe physical end-of-fir†°dONLNd§V bI)^le. When the logical end-of-fiQ°dONLNd¬VJbÏ)Ä%le is moved past the physical end-of-°dONLNdÁblnr(klfiå¿°dONLNdÈbrnS)2le, the File Manager automatically adds one or mor· °dONLNdbSn»)·e allocation blocks to the fi¿°dONLNd8b…nË)vle. The °dONLNd@nlz)(wl*number of allocation blocks added to the fi¬†°dONLNdkn)z)Ω-le is determined by the volume’s clump size. °dONLNdòzlÜs(ÉlA∫†°dONLNdôzsÜu) :†°dONLNdözvÜí)clump‡°dONLNdüzìÜ∞) is a gr`°dONLNdßz∞Üœ)@oup of contiguous allocation blocks. The purpose of always enlar*`°dONLNdÁzœÜÂ(Éœging °dONLNdÏÜlír(èlfiå¿°dONLNdÓÜríÎ)les by adding clumps is to r(°dONLNd
  365. ÜÏí)zeduce fi€ °dONLNdÜíÿ)"+le fragmentation on a volume and hence impr `°dONLNd=ÜŸíÎ)Àove °dONLNdAílûÑ(õlthe efÕ@°dONLNdGíÑûä)fi⁄°dONLNdIíäû∑) ciency of r[`°dONLNdTí∏û).eading and writing fi¿¿°dONLNdiíû5)]le data.
  366. √*…¯4ƒ*…¯ ƒlƒ¯
  367. ˇ·ˇ‚7^ˇˇ◊ˇ◊°dONLNdr≤l√â(ølFile ¸P°dONLNdw≤à√ )Access Characteristicsˇˇˇˇˇˇ®(ø1
  368. °dONLNdé…l’s(“lA∫†°dONLNdè…s’{) fiG`°dONLNdí…|’Í)    le can be open or closed. I‡°dONLNd¨…Í’)nY
  369. `°dONLNd≠…’Ê)8our application can perform certain operations, such as °dONLNdÂ’l·o(filrE°dONLNdÊ’p·")'eading and writing data, only on open fi†`°dONLNd’"·Â)≤.les. It can perform other operations, such as °dONLNd<·lÌ›(Íldeleting, only on closed fi% °dONLNdW·fiÌÓ)rles. °dONLNd]Ûlˇ¬(¸lWhen you open a fiİdONLNdoÛ√ˇ )Wle, the File Manager rß`°dONLNdÖÛ ˇ†)]eads information about the fiµ‡°dONLNd¢Û†ˇ±)Äle fr¿°dONLNdßÛ≤ˇÛ)om its volume °dONLNdµˇl ê(land storß°dONLNdΩˇê ˘)$es that information in a ¯‡°dONLNd÷ˇ˘ ˇ)ifi†°dONLNdÿˇ G)le control block(‡°dONLNdˡG ‘)G  (FCB). The File Manager also crY‡°dONLNdˇ‘ Ï)çeates °dONLNd ly(lan —`°dONLNd y´) access pathù¿°dONLNd ¨–)3     to the fiø¿°dONLNd& –8)$le, a description of the r懰dONLNd@ 8Á)h'oute to be followed when accessing the °dONLNdgl#r( lfiå¿°dONLNdir#‚)le. The access path specifi"†°dONLNdÑ„#e)qes the volume on which the fi2‡°dONLNd°e#)Ç"le is located and the location of °dONLNd√#l/Ç(,lthe fiÍ °dONLNd…#Ç/y)8le on the volume. Each access path is assigned a unique ˘°dONLNd#y/)˜fi¿°dONLNd#Ä/€)le reference number∫°dONLNd#€/›)[ °dONLNd/l;∏(8l(some number grhİdONLNd&/∏;v)L-eater than 0) that your application uses to r<¿°dONLNdS/v;Ê)æefer to it. Multiple access °dONLNdo;lG(Dl!paths can be opened to the same fiZ`°dONLNdë;G)òle.°dONLNdïMlY¨(VlFor each open  °dONLNd£M≠YÛ)Aaccess path to a °dONLNd¥MÙY˙)Gfi¿°dONLNd∂M˙Yõ)%le, the File Manager maintains a curr‘İdONLNd€MõYÒ)°ent position marker °dONLNdÓMÚY˜)W, °dONLNdYleë(bl    called th: °dONLNd˘Yíeô)&e É¿°dONLNd˚Yôeü)fiüİdONLNd˝Yüe∑)le maW°dONLNdY∏eƒ)rk,÷`°dONLNdYƒe$)  to keep track of wherÁİdONLNdY$e_)`e it is in the fi% °dONLNd,Y`eñ)<le during a rzİdONLNd9YñeŒ)6ead or write °dONLNdFelqá(nlAoperation. The mark is the number of the next byte that will be rv °dONLNdáeáq˜(náead or written; each time °dONLNd°ql}ñ(zl a byte is r °dONLNd¨qó}Ì)+Lead or written, the mark is moved. When, during a write operation, the mark °dONLNd¯}lâo(ÜlrE°dONLNd˘}pâ)'eaches the number of the last byte curr‡°dONLNd }â)´ently allocated to the fi⁄°dONLNd9}â)dle, the File Manager adds °dONLNdSâlïä(ílanothe§@°dONLNdYâäï≤)    r clump t °dONLNdbâ≥ï—))o the fin¿°dONLNdjâ—ï€)le.°dONLNdnõlßr(§lY@İdONLNdoõrßï)ou can r√¿°dONLNdwõïß»)# ead bytes fr!¿°dONLNdÉõ…ß9)4om and write bytes to a fi∫¿°dONLNdùõ9ߌ)p$le either singly or in sequences of  °dONLNd¡õœß˜)ñ
  370. virtually °dONLNdÀßl≥ª(∞lunlimited length. ܰdONLNd›ߪ≥¡)OYFİdONLNdfiß¡≥)ou can specify wherÄ °dONLNdÒß≥:)Xe each r°dONLNd˘ß;≥È)"'ead or write operation should begin by 
  371. w0¯4w0¯
  372. w0Ê4v/w0ò>@Á@Áw0∞Ê√√√    @† ÁÂ@ÄÁÂX›Ï„ì5ÇÁÂe&≤íTŒÁÂ#e≤íT≈ÁÂ#XÓÏìì<åÁ√√· ‰· ‰· ‰· ‰· ‰
  373. ÀˇÄ˝
  374. À‡˝
  375. À ˝
  376. À ˝Δ√√√√ÛÄ!@‡BÅ¿ÒÛÄ!AÔBÇÛåy∫93Y¿Ûtrf≥ÄÒÛíöN%L‡ %4úJô¬@ÒÛíö6%LQ %4lJò¢@ÒÛ¸yfi93»¿¯ÛºrgëÄÒ
  377. ÚÈ Ï Ú‡Í¿Ï√√
  378. ÒÂÒ
  379. ÒÂÒ
  380. ÒÂÒ
  381. ÒÂÒ‰ˇáÈˇÄ˝ÙÚÃıˆ¿˝‰xÈ`˝‰0È ˝‰0È ˝√√√√‘˝Ä¸ÔˇD`Úˇ¿b Úˇ‡ˇÔˇ‡Úˇ¿Úˇ‡ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇò>@ÄÁ@ÄÁ∞0ÈÊÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡ÚˇÚˇ¯ˇÔˇ‡Úˇ" Úˇ¯ˇÔˇ‡F Úˇ˛Úˇ¯ˇ˛Ôˇ‡Úˇ˛Úˇ¯ˇ√˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β˛È@β
  382. ‰˛
  383. ‰˛
  384. ‰˛8È9åÏ&f˛$    ÈC!íÏiô˛&˛IÈq8ÇÏ)˛:ü    È    åÏ)c˛&ò    ÈI$êÏ)â˛9FÈ1ûÏ&ˆ˛Á‰˛Á‰˛
  385. ‰˛
  386. ‰˛
  387. ‰˛
  388. ‰˛
  389. ‰˛
  390. ‰˛
  391. ‰˛
  392. ‰˛
  393. ‰˛
  394. ‰˛
  395. ‰˛
  396. ‰˛√√√Â@ ‡ÚIJ  Ú    Ä$˛Âc€ëú·ªÊÚ    Îkt7gt¿ˇÂ”:]oÚö¸ú|ß쵇ˇÂî„R"QhÚö‹lD§í5˛Â„›—“·ëgÚîkº<úb4‡ˇ
  397. „Äϯ
  398. ‰ί√ÂÄÏhÔ ôâ˚ò>ÄúÁÄúÁÈ0ÊÂÅòÔ ¶Y˚    ◊Ò“îÔ_¿§hĸ    4¯2tÔ”‡•ºÄ¸Â    4¡2Ô”¶Ä¸Â    »¯Ã‰Ô#‡õ»Ä¸ÂÔ ˚ÂÔ@˚√√√√√√√√√√√√√√√√√√√√√òÅË@ÁHHE˛ê¢Ä˛ˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  399. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@Áw0∞Ê'ÅÅÅôÅÅÅôÅÅÅô&ÅùˇˇˇÛˇˇˆˇ˝ˇ¯ˇ˚ˇˇÅ∑'ÅûˇˇˇˇÛˇÙˇ˝ˇ¯ˇ¸ˇˇÅ∏@Åû    ˇˇˇˇˇˇ˛ˇˇ˛ˇ˝ˇˇˇ˛ˇ˛˛ˇˇˇˇˇˇˇˇˇ¸ˇÅ∏@Åû˛ˇ-ˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇ˛ˇ˚ˇˇÅ∏FÅüˇ˛    ˇˇˇˇˇˇ˛ˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇ˛ˇˇ˛ˇˇÅ∏CÅüˇ˛ˇˇˇˇˇ˛˛ˇ˛ˇ˛ˇ
  400. ˇˇˇˇ˛ˇˇˇˇ˝ˇˇ˛ˇˇÅ∑ÅÅÅôÅÅÅô ÅŎÅú ÅŎÅú ÅŎÅú ÅŎÅú ÅŎÅú ÎŎŎŎŒˇ‚ΡÅÅÅ–˛ˇ‰ΡÅÅÅŒˇ‰ÏˇˇÅÅÅŒˇ‰ ÏˇÅÅÅØÅÅÅôÅÅÅôÅÅÅôÅÅÅô<ëˇˆˇ¯ˇ˛ˇ˝ˇ¯ˇ˚˛ˇÅÌˇˆˇ¯ˇ˛ˇ˝ˇ¯ˇ˚˛ˇÉ6ëˇÏˇ˛ˇ˝ˇ¯ˇ¸ˇÅÍˇÏˇ˛ˇ˝ˇ¯ˇ¸ˇÅf롲ˇˇ˛˝ˇˇˇ˛ˇˇ˛˛ˇˇˇˇˇˇˇˇˇ˛ˇÅÏˇ˛ˇˇ˛˝ˇˇˇ˛ˇˇ˛˛ˇˇˇˇˇˇˇˇˇ˛ˇÇg롡ˇˇˇˇˇˇ˛ˇ˛ˇˇˇˇˇˇ˛ˇ˙ˇÅÌˇˇˇˇˇˇˇˇ˛ˇ˛ˇˇˇˇˇˇ˛ˇ˝ˇˇÉp롡ˇˇˇˇˇ˛ˇˇˇˇ˛ ˇˇˇˇˇˇ˛ˇˇ˛ˇˇÅÌˇˇˇˇˇˇˇ˛ˇˇˇˇ˛ ˇˇˇˇˇˇ˛ˇˇ˛ˇˇÉXë˚ˇ˛˝ˇ˛ˇ˝ˇ˛˛ˇˇˇˇ˝ˇˇ˛ˇˇÅÏ˚ˇ˛˝ˇ˛ˇ˝ˇ˛˛ˇˇˇˇ˝ˇˇ˛ˇˇÇÜˇÅªˇÅ‹ⲡÅΩ˛ˇÅ€ÅÅÅôÅÅÅôÅ˙ˇÅûˇÖÅ˙ˇÅûˇÖÅ˙ˇÅûˇÖÅ˙ˇÅûˇÖÍŎóˇ˝ÅˇΩˇ‚Ρˇíˇâˇˇˇˇúˇ•ˇˇ„ΡÅó˝ˇÅΩˇˇ‰ÏˇˇÅñˇˇÅªˇ‰ÏˇÅïˇˇÅªˇ‰ÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅñˇÈˇÍˇfiˇ⁄*ÎÅˇÔˇ¯ˇ˛ˇ˛ˇˇ˜Ñˇ˙ˇˇ˛ˇ˛ˇ˜ÉˇÙΡ‡‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡˝ˇÁˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙˇÊˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙˇÙéΡ˜‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡˝ˇÁˇı‡ˇˆ‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇ‡‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡˝ˇÁˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇfl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡˝ˇÁˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆéΡ˜‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡˝ˇÁˇı‡ˇˆ‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇfl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡˝ˇÁˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇ‡‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡˝ˇÁˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆéΡ˜‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡˝ˇÁˇı‡ˇˆ‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇ‡‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡˝ˇÁˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇfl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡˝ˇÁˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆéΡ˜‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡˝ˇÁˇı‡ˇˆ‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇfl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡˝ˇÁˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇ‡‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡˝ˇÁˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆéΡ˜‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡˝ˇÁˇı‡ˇˆ‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆòÅË@ÄÁHHE˛å£Ä˛ˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  401. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@ÄÁ∞0ÈÊ'Ρ‡‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡˝ˇÁˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇfl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡˝ˇÁˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆéΡ˜‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡˝ˇÁˇı‡ˇˆ‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇfl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡˝ˇÁˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇ‡‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡˝ˇÁˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆéΡ˜‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡˝ˇÁˇı‡ˇˆ‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇ‡‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡˝ˇÁˇ˛‡fl˛‡fl˛‡flˇ‡‡fl˛‡fl˛‡flˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆÎˇfl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡˝ˇÁˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆéΡ˜‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇˆ‡ˇı‡ˇˆ‡ˇˆ‡˝ˇÁˇı‡ˇˆ‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇËˇÙˇˆˇıˇ˜ˇıˇˆˇˆˇˆˇˆˇÙ˛ˇˆ‰Îˇfl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡ˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡ˇ˛‡fl˛‡fl˛‡˝ˇÁˇ‡fl˛‡fl˛‡fl‡‡ˇfl˛‡fl˛‡fl‡‡ˇıˇˆˇˆˇˆˇˆˇˆˇˆˇÙ˛ˇ˚ˇ˛ˇ˛ˇ˜ÅˇˆÎÅˇÏˇ˚ˇ˛ˇˇ˛ˇ˜ÇˇÂÑˇˆÈŎӎÂÑˇÂÑˇˆÅÅÅô¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓ¡Å∏ˇÎˇˆˇÅƒˇıˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓD˜˛ˇ˚ˇ¯ˇˇÅ∫ˇÓ˛ˇˇ˝ˇ˚˛ˇˇ˛ˇˇÅ’ ˇˇˇˇˇˇˇ¸ˇÓO˜ˇˇ¸ˇ˘ˇˇÅªˇÔˇ˝ˇˇ˛ˇˇ¸ˇ˝ˇˇˇˇÅ◊ˇˇˇˇˇˇˇˇ˝ˇÓL˜ˇˇˇ˙ˇˇˇˇÅªˇÔ˛ˇ˛ˇ˝ˇ¸˛ˇ˛ˇ¸ˇÅ÷ˇˇˇ˛ˇ˛ˇ˝ˇÓJ˜˛ˇˇˇ¸ˇ˝ˇˇÅªˇÏˇˇ˝ˇ˘ˇˇ˛ˇˇÅ’ˇˇˇˇˇ˛ˇˇ˝ˇÓO˜
  402. ˇˇˇˇˇˇ˙ˇˇÅªˇÔˇˇˇ˝ˇ¸    ˇˇˇˇÅ”ˇˇˇˇ˛ˇˇ˝ˇÓK˜˛ˇˇ˛¸ˇˇ˛ˇˇÅ∫ˇÓˇˇ˛ˇ˝ˇ˚ˇˇ˛ˇ˝ˇÅ÷ˇˇˇ˝ˇˇˇ¸ˇÓÚˇÅ´ˇÅîˇÓÛˇÅ™ˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅõˇÅîˇÓÅÅÅôÅÅÅôÅÅÅô;Åúˇˆˇ¯ˇÛˇ¯ˇ˛˛ˇÅ˛ˇˇˆˇ˘ˇÚˇ¯ˇ˛ˇˇÔ7ÅúˇÏˇÛˇ˘ˇ˛ˇˇÅˇˇˇÌˇÚˇ˘ˇ˛ˇˇÔwÅúˇ˛ˇˇ˛˝ˇˇˇ˛ˇˇ˛ˇˇ˛ˇ˛ˇ˝ˇˇ˛ˇ¸ˇˇˇÑˇ˝ˇˇˇˇˇˇˇˇˇ˛ˇˇ˝ˇˇ˛ˇ˛˛ˇ˛ˇˇ˛ˇ˛ˇˇˇˇÛvÅú
  403. ˇˇˇˇ˛ˇ
  404. ˇˇˇˇ˝ˇˇˇˇ˛ˇˇˇ˛ˇˇˇˇ˝ˇÖ˛ˇˇˇˇˇ˚ˇˇ˛ˇ˛¸ˇˇˇ˝ˇˇ˛ˇˇˇˇ˝ˇÙ{Åú
  405. ˇˇˇˇ˛ˇ˛ˇˇˇˇˇ˝ˇˇˇˇ˛ˇˇˇ˛ˇˇˇˇÇˇ˛
  406. ˇˇˇˇˇˇ˛ˇ˛ˇˇˇˇ˛ˇ˛ˇˇˇˇˇˇˇ˛ˇˇˇˇÒrÅú˚ˇ˛˝ˇ˛ˇ˛ˇˇ˛˛ˇˇˇ˛ˇ˝ˇˇˇ˛ˇˇˇ˛ˇÖˇ˛ˇˇˇ˛ˇˇˇ˛ˇ˝ˇ˝˝ˇˇ˛ˇ˛ˇˇ˛ˇ˛ˇˇˇ˛ˇÙÅëˇÅÕˇøÅÅÕˇæÅÅÅô;Åúˇˇ˘ˇ˙˛ˇˇˇ˛ˇˇˇÅ͡ˇ˘ˇ¯ˇˇˇˇˇ˛ˇˇŸòÅËÄúÁHHE˛ê§Ä˛ˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  407. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêêÄúÁÈ0Ê'>Åúˇˇ˘ˇ˚ˇ˛    ˇˇˇˇˇÅ͡ˇ˘ˇ˘ˇˇˇˇˇˇˇˇˇŸFÅùˇ˛ˇˇ˙ˇ˛˛ˇ ˇˇˇˇˇÅÏˇ˛ˇˇ˙ˇ˚ˇˇˇ˛ˇˇˇ˛ˇ⁄IÅù ˇˇˇˇˇ¸ˇ¸ˇˇˇ˛ˇˇÅÏ
  408. ˇˇˇˇˇ¸ˇ¸    ˇˇˇˇˇ˝ˇˇ⁄JÅùˇˇˇˇˇˇˇ¸ˇˇˇˇ˝ˇˇÅÏ ˇˇˇˇˇˇˇ˘ˇˇˇˇ¸ˇ˛ˇ⁄IÅùˇ˛ˇˇ˛¸ˇ˛ˇˇˇˇ˛ˇˇÅÏˇ˛ˇˇ˛¸ˇ¸ˇˇˇ˝ˇˇ˛ˇ⁄Åúˇ˚ˇÍˇÅ͡¸ˇÂˇŸÅúˇ¸ˇÈˇÅ͡˝ˇ‰ˇŸÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôò>@Á@Á0;Ê√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√#˘|¿|‡    Ä``0AÄöÈ#˘D˛    D@ ˛     ˛¡Ä
  409. ÜÈ#˘@˛@Ä0Dz@˛ÅÈ$˘pŒ÷Ñ pÄPÇlj^_'6ūֺÍ$˘ë¥SêÄêÇ¥“íähi)i$ÇBöP4hÍ$˘Å$¢Å    ¯Ñ§°îàH§PE"hQê(pÍ$˘ÇY, Å Ñ1'>    ÷º ê“ìOÇ؆LÄÍ%˙√πÙ<√8!Œ9ÿ‘§XpêúÏ5È 8xpͯD˛˛D˙Ä˚ Á¯D˛˛D˚˙¿Á¯8˙8˚˙ÄÁ√#˘ pÜ¡Ä x˛al ˝2¡ÄÍ!˘ c˝à˛!  ˝cÈ&˘ @eà˛AA@e@Ï&˘ ^9î@•c˜{@Ü9·A¡Oõû@    Ô£á84 •¶‡Ï&˘ JKi†©$ñR"ù#ID¶ÇFô4J@§ƒBD$d–©4⁄@Ï&˘ î"â¿≤E¢BIêÖHÇë(T@DàBÑ H‡≤$í@Ï&˘ ñîæ"O9¥E2âk¬ÊHñÄiÑà ù"&ÄÏ'˙!‰ÁY¡Æ4œ$9“"„årEáÂ∫w$Ä:IppË·Æ9$ÄÏ
  410. Ô ÓDÍ€DÍ€8Í√˘t¸÷˘0à¸÷˘P˛@÷˘ QÁêÇ⁄gö‚hÒÄÿ˘ êíSB-¢JM0R@ÿ˘ ˘cÇ)$TN §◊˙    $¥4Rd•ê@¥¿ÿ˙>À#Å√íK>éB#ÿò>@ÄÁ@ÄÁ;0tÊ˘˝’ ˘˝“ ˘˝“√˘¡Å¯@à‘˘cH¿ò‘˘ e@ Ä    @◊˘•FÑçi‡    G˙7ù†Ÿ˘©Cí(†    ILI"¿Ÿ˘≤Ç"Q@"ÑHâBÄŸ˙"Ñ!ßï`4≤êûEÿ˙ÆAƒ˙D:'‹êj9ÿÛ“√√√˘xĽđ˘9Ä˝Ç@‘˘Q@‘˘Q4£y⁄@‘˘Qîƒí,@‘˘¢(Dàî(Ä‘˘≥K)    ‰P    ”˙‚}…£ê&”√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√ò>ÄúÁÄúÁt0çÊ√√√√√√√√√√√√√√√√√√√√√√√√√√√√òÅË@ÁHHE˛å•IJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  411. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@Á0;Ê'ÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôf¿¸ˇˇˇÊˇˇ˚ˇ˛¸ˇ˛ˇ˜ˇ˚ˇˇ˚˛ˇÒˇˇıˇÏˇˇ˝˝ˇˇˇÚˇˇÙˇ¸¸ˇˆˇˇıˇ˚¸ˇˇˇˇÅ»k¿ˇ˛ˇ„ˇˇ¸ˇ˛ˇ˛ˇ˛ˇ˜ˇˇ¸ˇ˛ˇ˙ˇ„ˇˇÎˇ¸ˇˇˇ‰ˇˇ¸ˇ˛ˇıˇˆˇˇ¸ˇ˛ˇ˝ˇˇÅ»S¿ˇ›ˇ¸ˇ˝ˇ˚ˇˆˇ¸ˇˇ˝ˇ¸ˇ‚ˇÎˇ¸ˇ˛ˇˇ„ˇ˚ˇÚˇıˇ˙ˇ˘ˇÅ«¥¿˛ˇ˝ˇˇ˛ˇ    ˇˇˇˇˇˇ˝ˇ˚ˇˇ˚ˇ˝˛ˇ˝ˇˆˇ˝ˇˇ˝ˇ¸ˇ˚˛ˇ˝˛ˇˇˇˇˇ˛ˇˇˇˇ˙ˇˇˇ˝ˇ˝ˇˇ¸ˇˇˇ¸ˇˇ˛ˇˇˇˇˇ˝ˇˇˇˇ˚˛ˇ˛˝ˇ˝ˇˇ˚˛ˇ˝ˇ˚˛ˇ˝˛ˇ¸ˇÅÕ÷¡ˇˇ˛ˇˇˇˇˇ˛ˇˇˇˇ˛ˇˇˇ˙ˇ˝ˇ˝ˇˇ˝ˇˆˇ˛ˇˇ˝ˇ¸ˇ¸ˇ˛ˇˇˇˇˇˇˇˇˇˇˇ˚ˇˇ˛ˇˇˇˇˇ˚˛ˇ˛ˇˇˇˇˇˇˇˇˇˇˇˇˇˇ¸ˇˇ˝ˇˇˇˇˇ˚ˇ˛ˇˇ˙ˇˇ˛ˇˇˇ˛ˇˇˇÅŒ«¡ˇ˚ ˇˇˇˇˇ˛ˇ˝˛ˇ˘ˇ˝ˇ˝ˇ˚ˇ˚ˇˇ˝ˇ˚ˇ˛ˇ˝ˇ¸ˇ˝
  412. ˇˇˇˇˇ˝ˇ˛ˇˇ˚ˇ˛ˇˇˇˇ˛ˇ˚ˇ¸ˇˇ˛ˇˇˇ˛ˇˇ¸ˇ˛ˇˇ˚ˇ˚ˇˇˇ˛ˇˇˇˇ˝ˇˇ˛ˇˇˇ˚ˇˇ˝˛ˇÅÕ¬¡ˇ¸ˇˇˇˇˇˇˇˇ˝ˇˆˇ˝ˇ˝ˇ˚ˇ˝ˇ˚ˇ˚ˇ¸ˇ˝ˇ˝ˇˇ˛ˇ˛    ˇˇˇˇ˛ˇ¸ˇ¸ˇ˛ˇˇˇˇˇ˝ˇ˝ˇ¸ˇˇ˝ˇˇˇˇˇˇˇˇˇ¸ˇ¸ˇ˝ˇˇˇˇˇ˝ˇ˝ˇ˛ˇˇ˘ˇ¸ˇˇˇˇÅ ¥¬˛ˇ˝˛ˇ˛ˇ¸ˇˇ¸˛ˇ˝˝ˇ¸ˇ˛˛ˇ˝˚ˇ˚˛ˇ¸ˇ˝ˇ˝˚ˇ˛ˇ˛˛ˇ˛ˇˇˇ˛ˇˇˇˇ˙ˇˇˇˇˇ˛ˇˇˇ˝˛ˇ˝ˇˇ˝ˇ˛ˇ˛ˇˇˇ˝ˇˇˇˇ¸˚ˇˇˇ˛ˇˇˇ˚˛ˇˇ˙˛ˇ˝˝ˇ˝˛ˇÅÕ$∏ˇ˛ˇ‰ˇfiˇˇ˛ˇ«ˇ»ˇÅ¥%∏ˇ˛ˇ„ˇ‡ˇÔˇ˛ˇ»ˇ…ˇˇÅ≥∑˛ˇ¡ˇÌ˛ˇ…ˇˇ»ˇÅ≤ÅÅÅô^¿˛ˇˆˇˇ˝ˇˇ¯ˇˇ¸ˇˇÙˇˇÌˇˇˆ˝ˇÂˇˇ˝¸ˇ¸ˇˇˇˇ¸ˇˇÙˇ¯˛ˇ›¸ˇˇˇˇ¯ˇˇ¸ˇˇÅ QøˇÓˇ˜ˇˇ˛ˇˇ‹ˇ˜ˇ˛ˇ‰ˇ˝ˇ˛ˇ˚ˇÍˇ˜ˇ‹ˇ˛ˇ¸ˇˇ˜ˇˇ˛ˇˇÅ…\¿ˇÓˇˆˇˇˇˇÎˇÙˇˆˇ˛ˇÂˇ¸ˇ¯ˇ¸ˇˇ˜ˇ˘ˇÒˇıˇ¯ˇˆˇˇˇˇˇÅ€Δ¿ˇ˝ˇ˛˛ˇˇˇˇˇ˛ˇ˚ˇˇˇˇ˛ˇˇˇˇˇ˛˚ˇ˛ˇ˛˛ˇ˛˝ˇˇˇ¯ˇ˚ˇ˝ˇˇ˛˛ˇ˝ˇ˝ˇˇ¸˛ˇ¸ˇˇ¸ˇˇˇ˛ˇ˝ˇˇ˜ˇ˝ˇ¸ˇˇ˛˛ˇ˝˛ˇ˛ˇ˚˛ˇ˝ˇˇˇ˝ˇ¸ˇˇˇˇ˝¸ˇˇˇˇ˛ˇÅ‹Û¿ˇˇˇˇˇˇˇˇˇˇˇˇˇ¸ˇˇˇˇˇˇˇˇˇˇˇˇˇ˛ˇ˛ˇˇ˛ˇˇ˜ˇ˛ ˇˇˇˇˇˇ˛ ˇˇˇˇˇˇ¸ˇˇ˛ˇˇˇˇˇˇˇˇˇ˛ˇˇˇˇ˜ˇ˛    ˇˇˇˇˇ˛ˇ˛ˇ˝ˇˇ˛ˇ˝ˇˇ˛
  413. ˇˇˇˇˇˇ˝ˇˇˇˇˇˇˇˇˇˇˇˇˇÅ€Â¡ˇˇˇ˝ˇ˛ˇˇ˛ˇ˛ˇ˚    ˇˇˇˇˇ˛ˇˇ¸ˇˇˇ˛ˇˇ˝    ˇˇˇˇ˙ˇ˛ˇ˛ˇˇ˝ˇ˝ˇˇˇˇ˛ˇ¸ˇ¸ˇ˛ˇˇ˛ˇˇˇ˝ˇˇˇ˛ˇ¯ˇ˛ˇˇ˛ˇˇ˛ˇ˝ˇ˝ˇˇ˝ˇ˝ˇ˚ˇˇ˛˛ˇ¸ˇˇˇˇ˛ˇˇˇˇˇˇÅ€fl¡ˇˇˇˇˇˇˇˇ¸ˇ˘ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇˇˇ˛ˇ˛    ˇˇˇˇˇ˘ˇ˛ˇˇ¸ˇ˛ˇ˛    ˇˇˇˇˇ˝ˇ˝ˇ˝ˇˇ¸ˇ    ˇˇˇˇ˛ˇˇˇˇˇ˜ˇ˛ˇˇˇˇˇ˝ˇ˛ˇ˝ˇˇ˛ˇ¸ˇ¸ˇ˛ˇˇ˙ˇˇ˛ˇ˝ˇˇˇˇˇˇˇÅ⁄›¬˝ˇˇ˛ˇ˛ˇˇˇˇ˛ˇ¸ˇˇˇ˛ˇ˛    ˇˇˇˇˇ˝ˇˇˇ˝˛ˇ˛ˇˇˇ˛ˇ˛ˇ˛ˇ˛˛ˇ˛ˇˇ˛˛ˇˇˇ˛ˇˇˇ˝˚ˇˇˇˇ˛ˇˇ˛ˇ˛ˇˇˇˇ¯˛ˇ
  414. ˇˇˇˇ¸˛ˇ¸ˇ˛˛ˇ¸˛ˇ˝˛ˇˇ˛˛ˇ˝ˇˇˇ˛ˇ˛˛ˇ ˇˇˇˇÅ⁄ÅÔˇÅ„ˇ˛ˇÅœÅÅ–ˇ˛ˇÅœ ÅÅœ˛ˇÅŒÅÅÅôæˇÒˇı˛ˇˇ“˛ˇÅűøˇˇÚˇˇˆˇ˛ˇ–ˇÅÅ∞ ¿ˇˇÚˇˆˇ˝ˇÂˇÓˇÅÅØT¿ˇˇ˛˝ˇ˝ˇˇ˝ˇ¸ˇ˘˛ˇ
  415. ˇˇˇˇˇ˝ˇˇˇˇ˛ˇ˛ˇˇˇˇ˘ˇ˝ˇ˛ˇˇÅÅ∫_¡ˇˇ˝ˇˇˇˇˇˇˇˇ˝ˇ˙ˇ˛ˇˇˇˇˇˇ˛ˇˇˇˇˇˇˇˇˇˇ¯ˇ˛ˇˇˇˇÅŪU¡¸ˇˇ˛ˇˇ˛ˇˇ˛˛ˇ¸ˇ˚ˇ˝ ˇˇˇˇˇ˛ˇˇˇ˛ˇ˛ˇ˛ˇ¯ˇ˛ˇˇˇÅÅ∑]¬ˇ˝ˇˇˇˇˇˇˇˇ˘ˇ˛ˇˇˇ˛ˇˇˇˇˇˇˇˇˇˇˇˇ¸ˇ˜ˇ˛    ˇˇˇˇˇˇÅŪ^√ˇˇ¸ˇ ˇˇˇˇˇˇ˛˛ˇ˚˛ˇ˝˛ˇˇˇˇˇˇˇ¸ˇˇ˛˛ˇˇ˝ˇ˝˛ˇˇˇ˛ˇˇ˝ˇÅÅæòÅË@ÄÁHHE˛ê¶Ä˛ˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  416. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêê@ÄÁ;0tÊ'ªˇ¸ˇ⁄ˇËˇÅÅ®ªˇ¸ˇ⁄ˇÅÅéº˛ˇ˛˛ˇ‹˛ˇÅÅèÅÅÅô,¡ˇˇ¸ˇˇ˚˚ˇ¯ˇˇ¯ˇˇÛ˛ˇˇ˛ˇÅÅû+¿ˇˇ˛ˇˇ˙ˇˇˇ¯ˇˇˇÊˇˇˇˇˇÅÅû/¿ˇˇˇˇ¯ˇ˜ˇˇˇÊˇˇ˛ˇÙˇÙˇÅÅπ^¡ˇˇˇˇ¯ˇ˛ˇˇˇ˝ˇˇ˛
  417. ˇˇˇˇˇˇ˝ˇ¯ˇˇ˛ˇˇˇˇ˛˘ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇÅŃf¡ˇˇˇˇ¯ˇ˝ˇˇ˛ ˇˇˇˇˇˇ˛ˇˇ˛ˇˇ¯ˇˇ˛ˇ˛ˇˇˇˇˇˇˇ˛    ˇˇˇˇ˛ˇˇˇÅÅ√`¡ˇˇˇˇ¯ˇ¸ˇ˝˛ˇˇˇ˛ˇˇˇ˛ˇˇ¯ˇˇ˛ˇ˛ˇˇ˝ˇ˛ˇˇ˛ˇ˛ˇˇˇ˝ˇˇÅŬa¬ˇˇ˛ˇ¯ˇ˝ˇ˝ˇ˝ˇˇˇ˝ˇ    ˇˇˇˇˇ˘ˇˇˇˇˇˇˇˇˇˇˇˇ˝ˇ˝ˇˇ˛ˇˇÅÅ¡b¬ˇˇˇ˛ˇˇ¸˛ˇ˛ˇ¸˛ˇˇ˛ˇˇˇ¸ˇˇˇ˛ˇ˝˛ˇˇ˛ˇ¸ˇ˛ˇˇˇ¸ˇˇˇˇ˛˛ˇˇÅÅ¡
  418. åˇÅÅèÅÅÅôÅÅÅôÅÅÅô¿˝ˇ˛ˇ‘ˇˇ˙ˇˇÅÅöø˛ˇˇˇ’ˇˇ¸ˇˇÅÅõ$¿ˇˇ˛ˇÙˇÙˇÓˇ¸ˇ˛ˇÅÅõ=¿ˇˇ˛ˇˇˇˇ˛˘ˇˇ˛ˇˇ˝ˇ˛ˇˇˇˇ˚ˇˇ¸ˇ˝ˇÅÅõB¿ˇˇ˛ˇ˛ˇˇˇˇˇˇˇ˛    ˇˇˇˇ˛ˇˇˇ¯ˇ˝ˇ˝ˇÅÅõ@¡ˇˇ˛ˇ˛ˇˇ˝ˇ˛ˇˇ˛ˇ˛ˇˇˇ˝ˇˇ˜ˇ˝ˇ˛ˇÅÅö>¡ˇˇˇˇˇˇˇˇˇˇˇˇ˝ˇ˝ˇˇ˛ˇˇˆˇ˝ˇˇÅÅô:¬˝ˇ˛ˇ¸ˇ˛ˇˇˇ¸ˇˇˇˇ˛˛ˇˇ˙˝ˇ˛ˇˇˇÅÅòÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôòÅËÄúÁHHE˛åßIJˇˇˇˇˇˇˇˇˇˇÃÃˇˇˇˇôôˇˇˇˇffˇˇˇˇ33ˇˇˇˇˇˇÃÃˇˇˇˇÃÃÃÃˇˇÃÃôô    ˇˇÃÃff
  419. ˇˇÃÃ33 ˇˇÃà ˇˇôôˇˇˇˇôôÃÃˇˇôôôôˇˇôôffˇˇôô33ˇˇôôˇˇffˇˇˇˇffÃÃˇˇffôôˇˇffffˇˇff33ˇˇffˇˇ33ˇˇˇˇ33ÃÃˇˇ33ôôˇˇ33ffˇˇ3333ˇˇ33ˇˇˇˇˇˇÃàˇˇôô!ˇˇff"ˇˇ33#ˇˇ$ÃÃˇˇˇˇ%ÃÃˇˇÃÃ&ÃÃˇˇôô'ÃÃˇˇff(ÃÃˇˇ33)ÃÃˇˇ*ÃÃÃÃˇˇ+ÃÃÃÃÃÃ,ÃÃÃÃôô-ÃÃÃÃff.ÃÃÃÃ33/ÃÃÃÃ0ÃÃôôˇˇ1ÃÃôôÃÃ2ÃÃôôôô3ÃÃôôff4ÃÃôô335ÃÃôô6ÃÃffˇˇ7ÃÃffÃÃ8ÃÃffôô9ÃÃffff:ÃÃff33;ÃÃff<ÃÃ33ˇˇ=ÃÃ33ÃÃ>ÃÃ33ôô?ÃÃ33ff@ÃÃ3333AÃÃ33BÃÃˇˇCÃÃÃÃDÃÃôôEÃÃffFÃÃ33GÃÃHôôˇˇˇˇIôôˇˇÃÃJôôˇˇôôKôôˇˇffLôôˇˇ33MôôˇˇNôôÃÃˇˇOôôÃÃÃÃPôôÃÃôôQôôÃÃffRôôÃÃ33SôôÃÃTôôôôˇˇUôôôôÃÃVôôôôôôWôôôôffXôôôô33YôôôôZôôffˇˇ[ôôffÃÃ\ôôffôô]ôôffff^ôôff33_ôôff`ôô33ˇˇaôô33ÃÃbôô33ôôcôô33ffdôô3333eôô33fôôˇˇgôôÃÃhôôôôiôôffjôô33kôôlffˇˇˇˇmffˇˇÃÃnffˇˇôôoffˇˇffpffˇˇ33qffˇˇrffÃÃˇˇsffÃÃÃÃtffÃÃôôuffÃÃffvffÃÃ33wffÃÃxffôôˇˇyffôôÃÃzffôôôô{ffôôff|ffôô33}ffôô~ffffˇˇffffÃÃÄffffôôÅffffffÇffff33ÉffffÑff33ˇˇÖff33ÃÃÜff33ôôáff33ffàff3333âff33äffˇˇãffÃÃåffôôçfffféff33èffê33ˇˇˇˇë33ˇˇÃÃí33ˇˇôôì33ˇˇffî33ˇˇ33ï33ˇˇñ33ÃÃˇˇó33ÃÃÃÃò33ÃÃôôô33ÃÃffö33ÃÃ33õ33ÃÃú33ôôˇˇù33ôôÃÃû33ôôôôü33ôôff†33ôô33°33ôô¢33ffˇˇ£33ffÃç33ffôô•33ffff¶33ff33ß33ff®3333ˇˇ©3333ÃÙ3333ôô´3333ff¨333333≠3333Æ33ˇˇØ33ÃÃ∞33ôô±33ff≤3333≥33¥ˇˇˇˇµˇˇÃÃ∂ˇˇôô∑ˇˇff∏ˇˇ33πˇˇ∫ÃÃˇˇªÃÃÃúÃÃôôΩÃÃffæÃÃ33øÃÿôôˇˇ¡ôôÃìôôôô√ôôffƒôô33≈ôôΔffˇˇ«ffÃûffôô…ffff ff33ÀffÃ33ˇˇÕ33ÃÃŒ33ôôœ33ff–3333—33“ˇˇ”ÃÑôô’ff÷33◊ÿˇˇˇŸ˘`˘`˘`⁄Ú–Ú–Ú–€Ï@Ï@Ï@‹Â∞Â∞Â∞›fl fl fl fiÿêÿêÿêfl“““‡ÀpÀpÀp·ƒ‡ƒ‡ƒ‡‚æPæPæP„∑¿∑¿∑¿‰±0±0±0™†™†™†Ê§§§ÁùÄùÄùÄËñññÈê`ê`ê`Íâ–â–â–ÎÉ@É@É@Ï|∞|∞|∞Ìv v v ÓoêoêoêÔiiibpbpbpÒ[‡[‡[‡ÚUPUPUPÛN¿N¿N¿ÙH0H0H0ıA†A†A†ˆ;;;˜4Ä4Ä4į---˘'`'`'`˙ – – –˚@@@¸∞∞∞˝   ˛êêêÄúÁt0çÊ'ÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôÅÅÅôˇÜ@ˇ ˇˇˇˇ@
  420. ˇ·ˇ‚7^
  421. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä About Files
  422. ‡(‡1ù)-‡)7(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿
  423. °dONLNd\äh(eäSsetting the mark; if you don’t, the operation begins at the byte at which the mark °dONLNdShätú* currذdONLNdWhút–) ently points4†°dONLNdch—t”)5.°dONLNdezäÜÛ(ÉäEach time you want to r °dONLNd|zÙÜ9)jead or write a fi±`°dONLNdçz9Ü‘)E$le’s data, you need to pass the addr_¿°dONLNd±z’ܘ)ú    ess of a Ï¿°dONLNd∫z˜Ü )"data °dONLNdøÜäíö(èäbufmİdONLNd¬Üöí¶)fer® °dONLNd≈ܶí®) ,( °dONLNdΔÜ©í˚)M a part of RAM (usually in your application’s heap) the File Manager uses to °dONLNdíäûÛ(õätransfer the data to or fr«‡°dONLNd-íÛûQ)iom your application. ô°dONLNdBíRûX)_YYİdONLNdCíXûº)ou can use a single bufí`°dONLNdZíºûÙ)dfer for each rÆ¿°dONLNdhíÙû)8ead or °dONLNdoûä™&(ßä#write operation, or change the addr@°dONLNdíû'™à)ùess and size of the buf ¿°dONLNd©ûà™Õ)afer as necessary¿°dONLNdπûÙŒ)D.°dONLNdª∞äº?(πä(When your application writes data to a fiø`°dONLNd‰∞?ºÔ)µ*le, the File Manager transfers the data frÔ °dONLNd∞Ôºˇ)∞om °dONLNdºä»(≈äyour application’s data bufưdONLNd,º»e)wfer and writes it to the ‡°dONLNdEºf»ó)e disk cache,¸¿°dONLNdPºó»)1 a part of RAM (usually in °dONLNdk»ä‘b(—ä1the System heap) that acts as an intermediate buf©Ä°dONLNdú»b‘Ø)ÿfer when data is r≈İdONLNdƻؑ»)Mead frC¿°dONLNd¥»…‘)om and written °dONLNd√‘䇴(›äto the fi"°dONLNdѨ‡‰)" le system. W= °dONLNdÿ‘‰‡F)8hen your application r£¿°dONLNdÓ‘F‡£)bequests that data be r^ °dONLNd‘§‡Ω)^ead fr‹`°dONLNd
  424. ‘Ω‡€)om a fi2†°dONLNd‘‹‡ )le, the File °dONLNd‡äÏ≠(ÈäManage`°dONLNd$‡ÆÏ·)$r looks for t/‡°dONLNd1‡·Ï¸)3he dat©°dONLNd7‡¸Ï)a in t• °dONLNd=‡Ï)hvİdONLNd>‡Ïf)e disk cache and tª`°dONLNdP‡fÏ)N'ransfers it to your application’s data °dONLNdwÏä¯ò(ıäbuf5°dONLNdzÏô¯°)feRİdONLNd|ϰ¯∑)Br if the data is found in the cache; otherwise, the File Manager r‡°dONLNdæÏ∏¯‚(ı∏
  425. eads the r‡†°dONLNd»Ï‚¯ )*    equested °dONLNd—¯ä´(äbytes frx†°dONLNdŸ¯´k)!*om the disk and puts them in your data buf‚ °dONLNd¯kw)¿fer4‡°dONLNd¯wy) .
  426. H4H°dONLNdˇˇ(äNOTE
  427. ˇ·ˇ‚7^
  428. °dONLNdä'ê* Y@İdONLNd    ê'«)ou can also rfi†°dONLNd«' )7ead a continuous str¸`°dONLNd* '°)Yeam of characters or a line of °dONLNdI'ä3¿(0ächaracters fr˘°dONLNdV'¿3fi)6om a fiO@°dONLNd]'fl3) le. In the fi@°dONLNdj'3∞)/&rst case, you ask the File Manager to °dONLNdê3ä?ç(<ärE°dONLNdë3é?ƒ) ead a specifiòİdONLNdû3ƒ?ó)6-c number of bytes: When that many have been r ¿°dONLNdÀ3ò?∏)‘ead, or °dONLNd”?äK”(Häwhen the mark rªÄ°dONLNd‚?”KH)Ieaches the logical end-of-fiç`°dONLNd˛?IKj)v    le, the ra¿°dONLNd?jK©)!ead operation °dONLNdKäW/(Tä'terminates. In the second case, called Ÿ`°dONLNd<K/Wp)• newline mode°dONLNdHKqWä)B, the r=`°dONLNdOKäWú)ead °dONLNdSWäc≤(`äCoperation terminates when either of the above conditions is met or °dONLNdñcäo…* when a specifi±Ä°dONLNd§c…oˇ)? ed character¸†°dONLNd∞c˛oa)5, the newline characterİdONLNd«cbot)d, is rᇰdONLNdÕctoú)    ead. The °dONLNd÷oä{⁄(xänewline characterJİdONLNdÁo€{µ)Q3 is usually Return (ASCII code $0D), but it can be °dONLNd{äá≈(Ñäany characterF@°dONLNd'{≈áØ);4. Information about newline mode is associated with °dONLNd[áäìÌ(êäeach access path to a fi    ‡°dONLNdsáÓì,)dle, and can dif°dONLNdÇá,ìA)>fer fræ°dONLNdàáAì£)om one access path to °dONLNdûìäü¨(úäanotherŸÄ°dONLNd•ì´ü≤)!;. See the chapter “The File Manager” in this volume for mor©¿°dONLNd‡ì≥ü∫(ú≥e °dONLNd‚üä´(®äinformation about newline mode醰dONLNdü´)í.,Zapf Dingbats†°dONLNdˇˇ)u
  429. —H◊4—H÷ —ä—
  430. ˇ·ˇ‚7^ˇˇ◊ˇ◊°dONLNdøä–’(Ãä
  431. The Hierar´†°dONLNd ø’–O)Kchical File Systemˇˇˇˇˇˇ®(Ã1
  432. °dONLNd3÷ä‚v(flä2The Macintosh Operating System uses a method of orC‡°dONLNde÷w‚¶)Ì
  433. ganizing fib`°dONLNdp÷¶‚·)/les called the °dONLNd‚äÓ»(Îähierarchical fiˆ†°dONLNdé‚»Ó)>le system (HFS). °dONLNdû‚Ó?)K
  434.  In HFS, fiu°dONLNd©‚?ÓV),les ar©°dONLNdØ‚VÓf)e grF¿°dONLNd≥‚gÓô) ouped into İdONLNdæ‚öÓ )3 directoriesj¿°dONLNd…‚ Ó)0 (also called °dONLNd◊Óä˙™(˜äfolders∂@°dONLNdfiÓ™˙ ) ), which themselves arn¿°dONLNdÙÓ˙)ce gr İdONLNd¯Ó˙w)ouped into other dirp‡°dONLNd Ów˙‰)Yectories, as illustrated in °dONLNd(ÓÂ˙˝)nFigurÁ¿°dONLNd-Ó¸˙ )e 1-°dONLNd1˙äè(ä4°dONLNd2˙è). The number listed for eacWİdONLNdM˙)vh dƒ†°dONLNdP˙)irr°dONLNdR˙G) ectory is it5†°dONLNd^˙HN).s Ú†°dONLNd`˙Nà)directory ID.C`°dONLNdm˙â´); The dir»@°dONLNdu˙´º)"ecto∫°dONLNdy˙ΩÚ)ry ID is one °dONLNdÜä◊(äcomponent of a fi∂@°dONLNdó◊)Mle system specifiøÄ°dONLNd®Õ)H*cation, as explained in the next section, _‡°dONLNd“Œ)Ø“Identifying °dONLNdflä¬(äFiles and Dir>@°dONLNdÏ√Ï)9
  435. ectories.”놰dONLNdˆÏÓ)).ˇD^@ˇ ˇˇˇˇ@
  436. ˇ·ˇ‚7^
  437. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  438. (‡*1 )-c)8    )9 About Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯
  439. g*w¯4g*w¯"g*_
  440. ˇ·ˇ‚7^    °dONLNdˇˇ(dl
  441. Figure 1-4°dONLNd\Æg )BThe Macintosh hierarchical fi °dONLNd\!gF)s    le system
  442. °dONLNd'elq¨(nlThe Finder is r«°dONLNd6e¨q1)@esponsible for managing the fiô °dONLNdTe2q‚)Ü)les and folders on the desktop. It works °dONLNd}ql}(zl(with the File Manager to maintain the orE†°dONLNd•q}a)≥ganization of fi÷@°dONLNdµqa}Û)B!les and folders on a volume. The °dONLNd÷}lâÜ(Ülhierarª°dONLNd‹}Üâ•)chical rdž°dONLNd‰}¶âú) 9elationship of folders within folders on the desktop corr0°dONLNd}ùâ—)˜ esponds dir!İdONLNd(}—âÛ)4    ectly to °dONLNd1âlïñ(íl
  443. the hierar`°dONLNd;âóïø)+
  444. chical dir‰ °dONLNdEâøïË)(
  445. ectory str5†°dONLNdOâÈï)*ucturªÄ°dONLNdTâïÔ)3e maintained on the volume. The volume is known as °dONLNdáïl°|(ûlthe ›`°dONLNdãï|°π)root directory·`°dONLNdôïπ°ª)=,a`°dONLNdöﺰ ) and the folders ar∑†°dONLNd≠ï °])Pe known as subdir—İdONLNdæï]°Ω)Qectories, or simply dirI °dONLNd’ïæ°‚)a    ectories.°dONLNdflßl≥s(∞lA∫†°dONLNd‡ßs≥·)Q volume appears on the desktop only after it has been mounted. Ejectable volumes °dONLNd1≥løΩ(ºl(such as 3.5-inch flÚ†°dONLNdE≥Ωø¸)Qoppy disks) ar!†°dONLNdS≥˝ød)@e mounted when they’rq °dONLNdh≥døfi)ge inserted into a disk drive; °dONLNdÜølÀ*(»l*nonejectable volumes (such as those on harÿ °dONLNd∞ø*ÀX)æ d disks) ar°dONLNdªøYÀˆ)/"e mounted automatically at system °dONLNd›Àl◊‚(‘lstartup. When a volume is x@°dONLNd˜À„◊)wmounted, °dONLNdˇÀ◊b), the File Manager rp°dONLNdÀb◊‹)Seads information about the °dONLNd-◊l„(‡l&volume into memory and places it in a 6`°dONLNdS◊„õ)≠volume control block (VCB).∫‡°dONLNdn◊õ„·)Ç The number of °dONLNd}„lÔ‘(ÏlPvolumes that can be mounted at any time is limited only by the number of drives °dONLNdÕÔl˚˜* attached and available memoryñ†°dONLNdÍÔˆ˚¯)ä.°dONLNdÏlv(
  446. lW°dONLNdÌvb)
  447. 4hen a volume is mounted, the File Manager assigns a  °dONLNd!cÿ)Ìvolume reference number‡°dONLNd8ÿÓ)u that °dONLNd>l(l"you can use to identify the volumeΔ °dONLNd`|)ô for as long as the volume rÖ¿°dONLNd|}«)xemains mounted„‡°dONLNdä«Ã)J. ∂@°dONLNdåÓ)Yv¿°dONLNdç“Ò)ou can °dONLNdîl%Î("lalso identify a volume by its Ô °dONLNd≤Î%+) volume name,`°dONLNdæ,%‰)A, a sequence of 1 to 27 printing characters, °dONLNdÍ%l12(.l-excluding colons (:). (The File Manager ignor~‡°dONLNd%21Á)Δ&es case when comparing names but does °dONLNd=1l=o(:lrE°dONLNd>1p=·)Qecognize diacritical marks.) Whenever possible though, you should use the volume °dONLNdè=lIo(FlrE°dONLNdê=pIÄ)eferÒ °dONLNdî=ÄIπ)Aence number to avoid confusion between volumes with the same nameª¿°dONLNd’=∫Iº(F∫.
  448. V*c¯4W*b¯°dONLNdˇˇ(^lNOTE
  449. ˇ·ˇ‚7^
  450. °dONLNd◊`lls* A∫†°dONLNdÿ`slù)     volume r(İdONLNd·`ûlÆ)+efer‘†°dONLNdÂ`Ælx).ence number is valid only until the volume is °dONLNdllx•(ul unmounted. C‡°dONLNdl•x¨)9A~İdONLNdl¨xÔ) single volume fl@°dONLNd.lÔx )Cthat is Z¿°dONLNd6lx/)mounteà¿°dONLNd<l/xú)"d, unmounted, and then °dONLNdSxlÑo(ÅlrE°dONLNdTxpѧ)
  451. emounted cH†°dONLNd^x§Ñ…)4an have [@°dONLNdfx…Ñ–)%a €@°dONLNdhx–Ñ‹)dif†°dONLNdkx›ÑÈ)ferË °dONLNdnxËÑ ) ent volume r3`°dONLNdzx!Ñ1)9eferflİdONLNd~x1Ñf)
  452. ence numbe2 °dONLNdàxgÑà)6r when °dONLNdèÑlêo(çlrE°dONLNdêÑpêü)    emounted.,Zapf Dingbatsÿ`°dONLNdˇˇ)2u
  453. °dONLNdÆñl¢.(ül-When an application ejects a 3.5-inch disk fr܆°dONLNd€ñ.¢fi)¬(om a drive, the File Manager places the °dONLNd¢lÆê(´lvolume ®‡°dONLNd
  454. ¢êÆô)$ofÓ°dONLNd ¢ôÆ¥)    f-line.i°dONLNd¢µÆ) When a volume is ofø`°dONLNd'¢Æy)]f-line, the volume contr†°dONLNd?¢zÆÚ)hol block is kept in memory °dONLNdZÆl∫∑(∑land the volume r8`°dONLNdjÆ∏∫»)Lefer‰Ä°dONLNdnÆ»∫‹)Aence number is still valid. If you make a File Manager call that 
  455. wlM¯4wlM¯
  456. wlM£4vkwlò(=8=8wl≤£ŸŸŸ˛ÏˇÏ?ˇÄÌ˝ˇÔ
  457. ˝ˇÄ
  458. ˝ˇÄ
  459. ˝ˇÄ
  460. ˝ˇÄ
  461. ˝ˇÄ
  462. ˝ˇÄ
  463. ˝ˇÄ
  464. ˝ˇÄ
  465. ˝ˇÄ
  466. ˝ˇÄ
  467. ˝ˇÄ
  468. ˝ˇÄ
  469. ˝ˇÄ
  470. ˝ˇÄ
  471. ˝ˇÄ
  472. ˝ˇÄ
  473. ˝ˇÄ
  474. ˝ˇÄ
  475. ˝ˇÄ
  476. ˝ˇÄ
  477. ˝ˇÄ
  478. ˝ˇÄ
  479. ˝ˇÄ
  480. ?˝ˇÄŸŸŸŸ     ÄÓ     ÄÓ
  481. -LÀFÔ
  482. )R ØÔ
  483. )R ®Ô
  484. å∫ßÔÔÏÔ ÏŸÓÌÓÌÓÌÓÌÓÌÓÌÓÌÓÌÓÌ
  485. ˘?Óˇ˛ˆ˘`˜˘ˆ˘@˜˘ˆ˘¿˜˘Ę˘Ä˜¯Ä˜˘Ä˜¯Ä˜˘Ä˜¯Ä˜¸ˇÄ˘˛˙ˇʸˇÄ̎˚ˇ¯Ä˜¸?ˇ¿Ä˘?ˇà˚ˇ¸Ä˜¸?˝ˇÄ˚˝ˇ˝˝ˇ˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸˝ˇ¿˚?˝ˇÄ˛˝ˇ¯˘ŸŸŸ˚Äꯠ@¸ !¯˚¯ @¸ !¯˚i毩¯¸Lv}…ò˘˚…ü¯©|¸^ü'+¸˘˚Iù¯it¸Pò;*4˘˚Gû¯'x˚éw?…ÿ˘Âˆ‡ˆ˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˜ˇ¸¸˝˘ˇ¸˚˝¸¸˝ ˘˚˝¸¸˝˘˚˝¸¸˝˘˚˝¸¸˝˘˚˝¸¸˝˘˚˝¸¸˝˘˚˝¸¸˝˘˚ˇˇ˛˛ˇ˝˝ˇˇ˛˘˚˛ˇ˛ˇÄ˛˝ˇˇÄ˘˚˛ˇIJˇ¿˛˝ˇˇ¿˘˚#˛ˇ¿˛ˇ‡ˇ˝ˇˇ‡ˇÄ˝?¯˚#˛ˇ‡˛ˇˇÇ˝ˇˇˇ¿˝¸˚#˛ˇ˛ˇ¯?ˇ¬˝ˇˇ¯ˇ‡˝ˇ˛˚#˛ˇ˛ˇ¯?˝ˇÄˇˇ¯˝ˇ¿˝ˇ¸¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸$˛ˇˇˇ¯˝ˇ¿?ˇˇ¯˝ˇ‡˛ˇ˛¸ŸŸŸ$Ä"˝¯Ä )@<xB˛Ä ˚$(Ä6˝  -@ @B˛@ ˚%!)‹±Ä64‹`&Œõ†-u“¯!ß;CNlL‡˚%!92˚¿6}2%)§‡-2|=Tö|“¯ü ˚%!E2√@*E2–%)£`m2t!TöD“àQ ˚%!E‹πÄ*<“`$Œù‡=.x=WCNxN‡˚˜˜Û˜˜Û˜˜˙˙
  486. ÙÔ˙
  487. ÙÔ˙
  488. ÙÔ˙
  489. ÙÔ˙
  490. ÙÔ˙
  491. ÙÔ˙˚Ùˇ¸ˆ˙˚x˛¸@˛Ę˙˚¿˛¸@˝¿˜˙˚IJ¸@˝@˜˙˚IJ¸@˝@˜˙˚IJ¸@˝@˜˙˚IJ¸@˝@˜˙˚IJ¸@˝@˜˙˝?ˇˇÄˇˇ¿ˇˇ‡ˇˇ˙ˇˇ¸˚˝?ˇˇ¿ˇˇ‡ˇˇˇˇ¯˙ˇˇ˛˚˝?ˇˇ‡ˇˇˇˇ¯ˇˇ¸˙˛ˇ˚ ˝?ˇˇˇˇ¯ˇˇ¸ˇˇ˛˙˛ˇÄ¸˝?ˇˇ¯ˇˇ¸ˇˇ˛˛ˇ˙˛ˇ¿¸!˝
  492. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  493. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  494. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  495. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  496. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  497. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  498. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  499. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  500. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  501. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  502. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  503. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  504. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  505. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  506. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  507. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  508. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  509. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  510. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  511. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  512. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  513. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  514. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  515. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸!˝
  516. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸˝
  517. ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˙˛ˇ‡¸ŸŸŸ˝8˝¿˝Å¯@˚˝$˝$ ˛A¯@˚ ˝'π‹ÊAå‹üÄ    ÂÛMlf˙fú¯Ã¸ ˝8‰r?BS2ó¿È5Ä”ûˇ˙ïFe˛¸ ˝'e≤›&Q2ó@i’nÄ1Pç˙ïZe¸ ˝9‰Úvé“wÄßr;/.v˙eNxϸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ#0ň Ɉ00¿`¿  M˘"˛ A        Çí `˝@ ˛`£˘&˝Ç(@Ñ † Ä@˛@DzĽ($3µ°≈(!@ÖÑ£L?sé∞X…¶ËÀçCŒG¬”˛($$mΔÄÑEH!@Üö$íe$R–i¥…1-2RAh&Içm˛($ I(áÑ"ë¢AúH†J(HêI8ë"    $"ÅpDéI˛($ ñKÑ"    $ A     $IÊõH• íA¬rLÁ¬&ÄIìì˛($pÓ}wppÉâ5ΔòÚG9 ìπAísÇ<pqí˛˛˛¸ÄÒ˚˛˛˝ ˚˛˘ ˚Ÿ˝>hɸc;‡¿Ì˝"Δ¸!1ÄÌ
  518.   ¸R"2Ä̪Np8pAJ5„GÄR"RÄÌëëàH—°RH§ökJ"TÄÌ%!    @°¡dâHírLDYÏ%¢"A2DùiÃÑÑDëÏy"‡··√\jFútƒÓ◊ÏÙ"ÈÙ"ÁÙÁŸŸŸŸŸŸŸŸŸŸŸŸŸ¸¿Á "˚ÄÁB˛Êy‰ ÄvôÊ∏ö<`Ë$$î–ÄãhíìLêË>E‡Å
  519. Ià)ÁBI-çô)d-0Ëœ≤»‡p‰íœ£êáH¬Ë˛Ç˝˛ÄÊ
  520. ˛Ç˝‚ «˝‚Ÿ ˛¿·
  521.     ˛    ‡
  522. ˛‡    „‰4Û¿„    kM$TÄ„ rI(°‚  ÅÜ"J≤‚    pséw}'Ä„˛Qfl˛Q fl˛é¿flŸ  ¸¿`‰`˝ ê‰
  523. @A‰
  524. MËfivÅlj
  525. E%1$ãB‰
  526. (ä"%
  527. B ‰
  528. ,“ ByB@‰
  529. xürA®‰âĉŸŸŸŸò(=8=8wl≤£ŸŸŸ˛ÏÏ0ÄÌ˝ˇÔ @˛Ä @˛Ä @˛Ä @˛Ä @˛Ä @˛Ä @˛Ä @˛Ä @Ä @Ä @Ä @Ä @Ä @Ä @˛Ä @˛Ä @˛Ä @˛Ä @˛Ä @˛Ä @˛Ä @˛Ä
  530. ˝ˇÄ
  531. ?˝ˇÄŸŸŸŸ     ÄÓ     ÄÓ
  532. -LÀFÔ
  533. )R ØÔ
  534. )R ®Ô
  535. å∫ßÔÔÏÔ ÏŸÓÌÓÌÓÌÓÌÓÌÓÌÓÌÓÌÓÌ
  536. ˘?Óˇ˛ˆ˘`˜˘ˆ˘@˜˘ˆ˘¿˜˘Ę˘Ä˜¯Ä˜˘Ä˜¯Ä˜˘Ä˜¯Ä˜¸ˇÄ˘˛˙ˇʸÄĢ˚Äʸ0¿Ä˘0à˚ ʸ?˝ˇÄ˚˝ˇ˝˝ˇ˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ Ä¿˚@qIJû˘¸ 1Ä¿˚@ãIJ`˘¸ Ä¿˚@    IJ|˘¸ Ä¿˚@1IJ¢˘¸ Ä¿˚@¡IJ"˘¸ Ä¿˚@˘IJ‹˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸ ˝¿˚@˛IJ˝˘¸?˝ˇ¿˚˝ˇÄ˛˝ˇ¯˘¸˝ˇ¿˚?˝ˇÄ˛˝ˇ¯˘ŸŸŸ˚Äꯠ@¸ !¯˚¯ @¸ !¯˚i毩¯¸Lv}…ò˘˚…ü¯©|¸^ü'+¸˘˚Iù¯it¸Pò;*4˘˚Gû¯'x˚éw?…ÿ˘Âˆ‡ˆ˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˙ˆ¯@˜˜ˇ¸¸˝˘ˇ¸˚˝¸¸˝ ˘˚˝¸¸˝˘˚˝¸¸˝˘˚˝¸¸˝˘˚˝¸¸˝˘˚˝¸¸˝˘˚˝¸¸˝˘˚ˇˇ˛˛ˇ˝˝ˇˇ˛˘˚    ÄIJ˝@Ģ˚    ÄÄ¿˛˝@¿˘˚#¿Ä`ˇ˝@`ˇÄ˝?¯˚#`Ä0Ç˝@0¿˝` ˚#į0¬˝@¯ `˝¿˚#˛0Ä?˝ˇÄ@˝ˇ¿˝ˇ¸¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸&˛0Ä ¿@8`Ä«¸&˛0Ä "¿@$@`Ä(ĸ&˛0Ä  ¿@ p`Ähĸ&˛0Ä  @¿@`Äĸ&˛0Ä 0@¿@"H`Äĸ&˛0Ä >@¿@0`ÄÔ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸$˛0Ä ˝¿@˝`IJ¸#˛ˇ˛ˇ¯?˝ˇ¿ˇˇ¯˝ˇ‡˝ˇ˛¸$˛ˇˇˇ¯˝ˇ¿?ˇˇ¯˝ˇ‡˛ˇ˛¸ŸŸŸ$Ä"˝¯Ä )@<xB˛Ä ˚$(Ä6˝  -@ @B˛@ ˚%!)‹±Ä64‹`&Œõ†-u“¯!ß;CNlL‡˚%!92˚¿6}2%)§‡-2|=Tö|“¯ü ˚%!E2√@*E2–%)£`m2t!TöD“àQ ˚%!E‹πÄ*<“`$Œù‡=.x=WCNxN‡˚˜˜Û˜˜Û˜˜˙˙
  537. ÙÔ˙
  538. ÙÔ˙
  539. ÙÔ˙
  540. ÙÔ˙
  541. ÙÔ˙
  542. ÙÔ˙˚Ùˇ¸ˆ˙˚x˛¸@˛Ę˙˚¿˛¸@˝¿˜˙˚IJ¸@˝@˜˙˚IJ¸@˝@˜˙˚IJ¸@˝@˜˙˚IJ¸@˝@˜˙˚IJ¸@˝@˜˙˝?ˇˇÄˇˇ¿ˇˇ‡ˇˇ˙ˇˇ¸˚˝ ¿‡p8˙˚˝ `∞X,˙ ˚ ˝ 0òL&˙    Ä¸ ˝ åF#˙¿¸!˝ ¸˛?Ä˚‡¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝  Ä˚˛`¸!˝
  543. ?ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˚˛ˇ‡¸˝
  544. ˇˇ¸ˇˇ˛˛ˇ˛ˇÄ˙˛ˇ‡¸ŸŸŸ˝8˝¿˝Å¯@˚˝$˝$ ˛A¯@˚ ˝'π‹ÊAå‹üÄ    ÂÛMlf˙fú¯Ã¸ ˝8‰r?BS2ó¿È5Ä”ûˇ˙ïFe˛¸ ˝'e≤›&Q2ó@i’nÄ1Pç˙ïZe¸ ˝9‰Úvé“wÄßr;/.v˙eNxϸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ#0ň Ɉ00¿`¿  M˘"˛ A        Çí `˝@ ˛`£˘&˝Ç(@Ñ † Ä@˛@DzĽ($3µ°≈(!@ÖÑ£L?sé∞X…¶ËÀçCŒG¬”˛($$mΔÄÑEH!@Üö$íe$R–i¥…1-2RAh&Içm˛($ I(áÑ"ë¢AúH†J(HêI8ë"    $"ÅpDéI˛($ ñKÑ"    $ A     $IÊõH• íA¬rLÁ¬&ÄIìì˛($pÓ}wppÉâ5ΔòÚG9 ìπAísÇ<pqí˛˛˛¸ÄÒ˚˛˛˝ ˚˛˘ ˚Ÿ˝>hɸc;‡¿Ì˝"Δ¸!1ÄÌ
  545.   ¸R"2Ä̪Np8pAJ5„GÄR"RÄÌëëàH—°RH§ökJ"TÄÌ%!    @°¡dâHírLDYÏ%¢"A2DùiÃÑÑDëÏy"‡··√\jFútƒÓ◊ÏÙ"ÈÙ"ÁÙÁŸŸŸŸŸŸŸŸŸŸŸŸŸ¸¿Á "˚ÄÁB˛Êy‰ ÄvôÊ∏ö<`Ë$$î–ÄãhíìLêË>E‡Å
  546. Ià)ÁBI-çô)d-0Ëœ≤»‡p‰íœ£êáH¬Ë˛Ç˝˛ÄÊ
  547. ˛Ç˝‚ «˝‚Ÿ ˛¿·
  548.     ˛    ‡
  549. ˛‡    „‰4Û¿„    kM$TÄ„ rI(°‚  ÅÜ"J≤‚    pséw}'Ä„˛Qfl˛Q fl˛é¿flŸ  ¸¿`‰`˝ ê‰
  550. @A‰
  551. MËfivÅlj
  552. E%1$ãB‰
  553. (ä"%
  554. B ‰
  555. ,“ ByB@‰
  556. xürA®‰âĉŸŸŸŸˇ#∏@ˇ ˇˇˇˇ@
  557. ˇ·ˇ‚7^
  558. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä About Files
  559. ‡(‡1ù)-‡)9(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿
  560. °dONLNd\äh¶(eäspecifiÓ °dONLNd\¶hC)#es that volume, the File Manager pr”¿°dONLNd*\Ch)ù-esents the disk switch dialog box to the user뇰dONLNdW\h
  561. )¬. °dONLNdYhät¢(qäFigurR¿°dONLNd^h¢t∂)e 1-5@°dONLNdch∂tf)' shows a sample disk switch dialog box.
  562. óH®4òH®"òH_
  563. ˇ·ˇ‚7^    °dONLNdˇˇ(ïä
  564. Figure 1-5°dONLNdãçÃò5)BThe disk switch dialog box
  565. °dONLNd¶äS(ä,When the user drags a volume icon into the Tˆ¿°dONLNd“R´)»rash, that volume is ú °dONLNdÁ¨„)Z
  566. unmounted;mİdONLNdÒ‰ˆ)8 the °dONLNdˆä ≈(ä volume contrg`°dONLNd≈ ˜);ol block is rİdONLNd¯ Î)37eleased, and the volume is no longer known to the File °dONLNdF ä,±()äManagerT†°dONLNdM ±,Ì)'. In particularπ°dONLNd\ Ï,));, the volume r@°dONLNdj *,:)>efer∞`°dONLNdn :,)ence number pr<¿°dONLNd| Ä,)F eviously assigned to the volume °dONLNdú,ä8Ÿ(5äis no longer valid.°dONLNd∞>äJæ* Each subdirÚ@°dONLNdª>æJ<)4ectory is located within a dir◊°dONLNdŸ><JÉ)~ectory called its X†°dONLNdÎ>ÑJÕ)Hparent directoryu‡°dONLNd˚>ÃJŒ)H.ı‡°dONLNd¸>ŒJ÷) T∞†°dONLNd˛>÷J˘)ypicallyfi†°dONLNd>¯J)", the °dONLNd JäVò(SäparG °dONLNdJôV∂)ent dirm†°dONLNdJ∂V˙)ectory is specifit†°dONLNd'J˙V)Ded by a ¿°dONLNd/JVv)"parent directory ID,0İdONLNdCJwVfl)[ which is simply the dirA¿°dONLNd[JflV)hectory ID of °dONLNdhVäb©(_äthe par§Ä°dONLNdoV©bΔ)ent dirÀ°dONLNdvVΔb·)ectory"¿°dONLNd|V·bè)(. The File Manager assigns a special par™¿°dONLNd§Vèb¨)Æent dir—@°dONLNd´V¨b)ectory ID to a volume’s °dONLNd√bänç(kärE°dONLNdƒbén´)oot dirªÄ°dONLNdÀb´nΔ)ectory@°dONLNd—bΔn·)B. This is primarily to permit a consistent method of identifying fiİdONLNdb‚n(k‚les and °dONLNdnäzñ(wädirI °dONLNdnóz)ectories using the volume rÙ¿°dONLNd:nz)wefer†‡°dONLNd>nzX) ence number(¿°dONLNdInXz|)9    , the parM@°dONLNdRn|zô)$ent dirs¿°dONLNdYnôz)ectory ID, and the fiZ@°dONLNdnnÒz)Xle or °dONLNdtzäÜñ(ÉädirI °dONLNdwzóÜ-)#ectory name. See the next section,  Ä°dONLNdöz-Üû)ñ“Identifying Files and Dirt†°dONLNd¥züÜ»)r
  567. ectories,”»°dONLNdæz»Ü˘)) for details.°dONLNdÃåäò    (ïäWFor the most part, your application does not need to be concerned about, or keep track °dONLNd#òä§fl* of, the location of fiº†°dONLNd9òfl§)U les in the fiœÄ°dONLNdFò§U)0le system hierar•†°dONLNdVòU§d)FchyZ†°dONLNdYòd§£). Most of the fi¯@°dONLNdiò£§˝)?les your application °dONLNd~§ä∞›(≠äopens and saves arΆ°dONLNdê§›∞)Se specifi£`°dONLNdô§∞)$=ed by the user or another application, and their location is °dONLNd÷∞äºì(πäprG °dONLNdÿ∞)
  568. >ovided to your application by either the Finder or the Standar @°dONLNd∞§º˝(π§d File Package. One °dONLNd*ºä»Ë(≈änotable exception herB¿°dONLNd?ºÈ»#)_e concerns pr≈İdONLNdLº#»3):eferq†°dONLNdPº4»T)ences fi@°dONLNdXºU»å)!les, which arñ†°dONLNdeºå»Õ)7e typically stor¶@°dONLNduºÕ»ı)A
  569. ed in the °dONLNd»ä‘ì(—äPrN†°dONLNdŻ)
  570. efer˙¿°dONLNdÖ»§‘    )ences folder in the curr\İdONLNdù»
  571. ‘~)fently active System Folder/¿°dONLNd∑»~‘î)t. See Ç¿°dONLNdΩ»î‘«) “Using a PrûİdONLNd»»«‘◊)3eferJ†°dONLNdûÿ‘) ences File”°dONLNd◊»‘
  572. )0 °dONLNdÿ‘ä‡≠(›ä    for instr”¿°dONLNd·‘≠‡„)# uctions on fiM`°dONLNdÓ‘‰‡
  573. )7nding pr Ä°dONLNdˆ‘
  574. ‡)&eferv†°dONLNd˙‘‡;)ences fi@°dONLNd‘<‡J)!les.
  575. ÓH˚4ÔH˙°dONLNdˇˇ(ıäNOTE
  576. ˇ·ˇ‚7^
  577. °dONLNd¯äœ* In addition to fiܰdONLNd¯œß)E3les, folders, and volumes, a user might also see a °dONLNdKäñ(ä>fourth type of object on the Finder desktop, namely an alias. %İdONLNdâñ¶(ñAn > °dONLNd嶪)aliasV °dONLNdëªΩ) °dONLNdíä‰(äis a special kind of fi©‡°dONLNd©‰)Z    le that rw°dONLNd≤)"epr¿°dONLNdµ])esents another fiL`°dONLNdΔ]Ñ)H
  578. le, folder ¿°dONLNd–É∫)&, or volume. °dONLNd›ä((%äThe Finder and the Standar[`°dONLNd˜(à)yd File Package automatically rU@°dONLNdà(¶)Öesolve °dONLNd(ä4¿(1äaliases beforÙ°dONLNd)(¿4©)65e passing them to your application, so you generally °dONLNd^4ä@\(=ä/don’t need to do anything with aliases. For mor` °dONLNdç4\@®)“e information on °dONLNdû@äLÂ(Iäworking with alias fi¿°dONLNd≥@ÊLΩ)\3les, see the chapter “The Finder Interface” in the °dONLNdÊLäX–(UäUser Interface T2İdONLNdˆL–Xt)F#oolbox volume and the chapter “The >¿°dONLNdLtX¨)§ Alias ManagiİdONLNd$L¨Xπ)8er”%¿°dONLNd'L∫Xº) °dONLNd(XädÃ(aäin this volume.,Zapf Dingbatsõ¿°dONLNdˇˇ)Eu
  579. âHè4äHè äää
  580. ˇ·ˇ‚7^ˇˇ◊ˇ◊°dONLNdLxäâ4(ÖäIdentifying Files and Dirmê°dONLNdex4âh)™ectoriesˇˇˇˇˇˇ®)⁄1
  581. °dONLNdnèäõ∑(òä
  582. The hierarˆ¿°dONLNdxè∑õ)-chical arrangement of fiê@°dONLNdêè õN)i les and dir5İdONLNdõèOõ‰)/#ectories allows you to identify a fi``°dONLNdøè‰õ˙)ïle or °dONLNd≈õäßñ(§ädirI °dONLNd»õó߈)ectory uniquely by prº¿°dONLNd›õˆß:)_oviding just thr€Ä°dONLNdÌõ:ß›)D&ee pieces of information: its volume rt °dONLNd    õfißÓ)§efer @°dONLNd    õÔß)ence °dONLNd    ßä≥¨(∞änumber≥°dONLNd    "ߨ≥Ã)"    , its para‡°dONLNd    +ßÕ≥Í)!ent dirà`°dONLNd    2ßÍ≥ï)'ectory ID, and its name within that par†°dONLNd    Yßñ≥≥)¨ent dir, °dONLNd    `ß≥≥Œ)ectoryɇ°dONLNd    fßÕ≥). The system 
  583. ßäÒ4®äÒòÄ$iHHEˇˇˇˇˇˇˇi¨ä>flˇ¯ććü‡ˇ»ü‡ˇ»ò‡œ‡ò‡» ò‡» ò‡œ ò‡œ ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À  ò˛UºÂÀ  òÂÀ  ò˝ÂÀ     ò>0˝`˛ Ä0˘À ò˝¿30˘ 0˘À !òÄ31··√¿g√áÜfiü˘é30˙À  ò˝3323&`ffL« ôÅôô60˙À ò˙>31ÛÜ`fg Δ ôÅôú<˘À  òˇ¯03Û1«‡fcèΔ üÅôé8˘À  òHà§030Êfaà òôá<˘À !òDà¢032f fdÃF òÅôì60˙À !òDà"01·Ò√¿fcáÜôè˘é30˙À òƒè‚ÊÀ òÄÊÀ òÄÊÀ ò?‰üÚÊÀ ò?‰üÚÊÀ ò@†
  584. ÊÀ ò@†
  585. ÊÀ ò@†
  586. ÊÀ ò@†
  587. ÊÀ ò@†
  588. ÊÀ ò@†
  589. ÊÀ òˇ¸ˇ˛ÊÀ ò˙˝¿Ä 0ÚÀ ò˝3¸ÅÄ 0ÚÀ ò36|x¯«√èxÒ∞ÙÀ òIJ 38ÃåÃÃÅÁëå1ô¿ÙÀ ò30Ã|ÃÃ}èå1ôÄÙÀ ò˝30˝Ã9ôå1˘ÄÙÀ     ò30˝Ãôå1ÅÄÙÀ ò˛ˆ®30˝ÃÅôå1âÄÙÀ ò˙ 0||ëèÜÒÄÙÀ  ò¯ ÍÀ  ò¯åÍÀ  ò¯xÍÀ ò‡À ò‡À ò‡À ò‡À ò‡À òÍ˚ˇ‡À òÍ0˚À òÍ ˚À òÍ@˚À òÍ@˚À òÍ@˝0À òÍ@IJ0À òÍ @0À òÍ @ôô30À òÍ @ôò30À òÍ @ôò?0À òÍ @ôò00À òÍ@˛ô10À òÍ @ôé0À òÍ@˚À òÍ@˚À òÍ@˚À òÍ ˚À òÍ0˚À òÍ˚ˇ‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ò‡À ü‡ˇÀ ü‡ˇÀ ć  ć  flˇ˚ ˇR@ˇ ˇˇˇˇ@
  590. ˇ·ˇ‚7^
  591. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  592. (‡*1 )-c)10    )9 Using Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯
  593. °dONLNd\lhç(elsoftwar‰¿°dONLNd\çh)!e lets you specify these thrl†°dONLNd#\hh)uee items together in a fi,`°dONLNd<\ih±)gle system specifi5†°dONLNdM\±h“)Hcation r\İdONLNdU\“h‰)!ecor–‡°dONLNdY\‰hÔ)d, .°dONLNd\hlt~(qldefi°dONLNd`h~tØ) ned by the ,
  594. Courier°dONLNdkhØt”)1FSSpec°dONLNdqh”t)$  data type:°dONLNd}Älå¥(âl TYPE FSSpec °dONLNdëÄΔåÃ)Z=°dONLNdñÄå∞)H{file system specification}°dONLNd≥élöê(ólRECORD°dONLNdæú~®Æ+vRefNum:°dONLNd úΔ®ˆ)HInteger;°dONLNd÷ú®§)H{volume reference number}°dONLNdı™~∂¢(≥~parID:°dONLNdˇ™Δ∂ˆ)HLongInt;°dONLNd ™∂⁄)H"{directory ID of parent directory}°dONLNd3∏~ƒú(¡~name:°dONLNd<∏Δƒ‰)HStr63°dONLNdB∏‰ƒÍ);°dONLNdF∏ƒ∂)*{filename or directory name}°dONLNddΔl“Ñ(œlEND;°dONLNdifilÍÄ*The °dONLNdmfiÄͧ)FSSpec°dONLNdsfi§Í™)$ rR`°dONLNdufi™Íº)ecor$¿°dONLNdyfiºÍŒ)d pr˜ °dONLNd}fiÕÍL)ovides a simple and standar…İdONLNdòfiLͺ)d format for specifying fi…İdONLNd≤fiºÍfi)ples and °dONLNd∫Ílˆz(ÛldirR`°dONLNdΩÍzˆ)"ectories. For example, the Standar$¿°dONLNdfl͈e)úd File Package pr˜ °dONLNdÍdˆÅ)Nocedur…İdONLNdˆÍňà)e …İdONLNd¯Íàˆ‚)StandardGetFile…İdONLNdÍ‚ˆ‰)Z °dONLNdˆlp(ˇlrR`°dONLNd    ˆp)%eturns information identifying a user$¿°dONLNd.ˆG)• -selected fi$¿°dONLNd:ˆGì)2le or folder in an $¿°dONLNdMˆì∑)LFSSpec$¿°dONLNdSˆ∑Ω)$ r˜ °dONLNdUˆºŒ)ecor…İdONLNdYˆŒŸ)d. õ‡°dONLNd\ˆŸ‡) Y∞‡°dONLNd]ˆflÎ)ou ˇ˛‹°dONLNd`l…( lcan pass that identifi–°dONLNdv Ù)^
  595. cation dirΔ °dONLNdÄÙ.)*ectly to any fi\°dONLNdè/~);le-manipulation r @°dONLNd†”)Poutines that accept ˇ¸ñ–£°dONLNd¥”˜)TFSSpecˇ˛‹£)$ °dONLNdªlp(lrR`°dONLNdºpÇ)ecor$¿°dONLNd¿Ç≥) ds, such as $¿°dONLNdÃ≥È)1    FSpOpenDF$¿°dONLNd’È˛)6 and $¿°dONLNd⁄˛4)    FSpDelete$¿°dONLNd„4É)6. In addition, the Δ`°dONLNdˆÇΔ)NAlias Manager    °dONLNdΔÔ)D
  596. , Edition °dONLNdl&î(#lManager¬†°dONLNdì&Î)', and Finder all use ¬†°dONLNd)Î&)XFSSpec¬†°dONLNd/&)$ rï°dONLNd1&')ecorg`°dONLNd5'&h)ds to specify fig`°dONLNdEh&ò)A les and dir9¿°dONLNdPò&ª)0ectories9¿°dONLNdXª&æ)#.
  597. +*F¯4,*F¯
  598. W*_¯4X*_¯ X*X˛
  599. ˇ·ˇ‚7^ˇˇ£‰.ˇÆ°dONLNdZD*V(R* Using Filesˇˇˇˇˇˇ⁄|(RÓ1
  600. °dONLNdfgls=(pl/This section describes how to perform typical fi¡`°dONLNdñg=sÓ)—)le operations using some of the services °dONLNdøslu(|lprG °dONLNd¡sv◊)
  601. ovided by the StandarÙ¿°dONLNd÷s◊f)a d File Package, the File Managerw@°dONLNdˆsfò)è , the Finder8 °dONLNdsòÎ)2, and other system °dONLNdlãç(àlsoftwar‰¿°dONLNdçãœ)!e components. KİdONLNd*–ã˛)C Listing 1-1ο°dONLNd5˛ã€).2 shows one way to handle some of the typical File °dONLNdgãlóö(îlBmenu commands. Most of the techniques described in this section arh °dONLNd©ãöófi(îöe illustrated by °dONLNd∫ól£ß(†l means of defiÁİdONLNd«óߣ7);#nitions of the functions called in "°dONLNdÍó8£f)ë Listing 1-1¬@°dONLNdıóf£h)..
  602. ≈*…¯4Δ*»¯"Δ*a
  603. ˇ·ˇ‚7^    °dONLNdˇˇ(√l Listing 1-1°dONLNd˜ª∞Δ;)DHandling the File menu commands
  604. .°dONLNd“lfiÄ(€l.PROCEDURE DoMenuCommand(menuAndItem: LongInt);°dONLNdF‡lÏ~*VAR°dONLNdNÓ~˙Ã+myErr: OSErr;°dONLNd\¸lä(lBEGIN°dONLNdf
  605. ~ +CASE HiWord(menuAndItem) OF°dONLNdáê$¥+mFile:°dONLNdî&¢2D+CASE LoWord(menuAndItem) OF°dONLNd∑4¥@“+iNew:°dONLNd≈BΔN2+myErr := DoNewCmd;°dONLNdfiBDNŒ)~{create a new document}°dONLNd˝P¥\ÿ(Y¥iOpen:°dONLNd ^Δj8+myErr := DoOpenCmd;°dONLNd&^DjÊ)~{open an existing document}°dONLNdIl¥xfi(u¥iClose:°dONLNdYzΔÜ>+myErr := DoCloseCmd;°dONLNdtzDÜÏ)~{close the current document}°dONLNdòà¥îÿ(ë¥iSave:°dONLNdßñΔ¢8+myErr := DoSaveCmd;°dONLNd¡ñD¢Ê)~{save the current document}ˇ@ˇ ˇˇˇˇ@
  606. ˇ·ˇ‚7^
  607. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä Using Files
  608. ~¿(‡1‡)-a¿)11(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿,
  609. Courier
  610. .°dONLNd\“h(e“iSaveAs:°dONLNdj‰vb+myErr := DoSaveAsCmd;°dONLNd*jbv)~{save document under new name}°dONLNdPx“Ñ(Å“iRevert:°dONLNda܉íb+myErr := DoRevertCmd;°dONLNd{Übí)~{revert to last saved version}°dONLNd°î“†(ù“    OTHERWISE°dONLNd≥¢‰ÆÍ+;°dONLNdª∞¿ºÿ(π¿END;°dONLNd≈æÆ ‰(«Æ    OTHERWISE°dONLNd’ÿÿΔ+;°dONLNd€⁄úÊ¥(„úEND;°dONLNd‡ËäÙ¢(ÒäEND;.°dONLNdÂä ê*Y@İdONLNdÊê Ò)Mour application should inactivate any menu commands that do not apply to the °dONLNd3 äë(äfrò‡°dONLNd5 ë‹)ontmost windowy°dONLNdC ‹=)K. For example, if the frù °dONLNd[ =)a(ontmost window is not a document window °dONLNdÉä$ê(!ä=that belongs to your application, then the Close, Save, Save `°dONLNd¿ë$(!ëAs, and Revert commands °dONLNdÿ$ä0w(-ä1should be dimmed when the menu appears. Similarly!İdONLNd    $w0ú)Ì , if the frT°dONLNd$ú0˚)%ontmost window is a °dONLNd(0ä<(9äTdocument window that does belong to your application but whose data has not changed °dONLNd|<äH‚* Jsince it was last saved, then the Save menu command should be dimmed. See °dONLNdΔHäT0* $“Adjusting the File Menu” on page 1-ù°dONLNdÍH0T:)¶33ù°dONLNdÏH:TÁ)
  611. ( for details on implementing this featur•@°dONLNdHÁT)≠e. The °dONLNdTä`ö(]ädefir °dONLNdTõ`)nitions of the application-defi˛ °dONLNd>T`~)Çned functions used in „`°dONLNdTT`≠)b Listing 1-1Ɇ°dONLNd_TÆ`˙)/ assume that this °dONLNdq`äl§(iäfeatur¨°dONLNdw`§l)e has been implemented.°dONLNdèrä~ê({äT†¿°dONLNdêrê~í):he techniques described in this chapter for manipulating fiÕ@°dONLNdÀrí~({íles assume that you identify °dONLNdË~ääê(áäfiå¿°dONLNdÍ~êäæ) les and dir2°dONLNdı~øä)/ectories by using fi5‡°dONLNd    ~äZ)Sle system specifi? °dONLNd~Zä{)Hcation rf°dONLNd"~{äç)!ecor⁄`°dONLNd&~çä÷)ds. Because the r8‡°dONLNd7~◊ä)Joutines that .°dONLNdDääñ©(ìäaccept °dONLNdKä©ñÕ)FSSpec°dONLNdQäÕñ”)$ rR`°dONLNdSä”ñÂ)ecor$¿°dONLNdWäÂñ˚)ds ar˜ °dONLNd\ä˙ñ”)1e not available on all versions of system softwar…İdONLNdçä”ñ)Ÿ e, you may .°dONLNdòñä¢<(üä,need to test for the availability of those rÑİdONLNdƒñ<¢v)≤outines beforcİdONLNd—ñv¢):$e actually calling any of them. See °dONLNdı¢äÆ”(´äthe next section, K‡°dONLNd¢‘Æfl)J“Tņ°dONLNd    ¢fiÆà)
  612. %esting for File Management Routines,”˜ °dONLNd.¢àÆπ)™ for details.
  613. ”HŸ4‘HŸ ‘ä‘
  614. ˇ·ˇ‚7^ˇˇ◊ˇ◊°dONLNd<¬ä”ì(œäT≠°dONLNd=¬í”ë)#esting for File Management Routinesˇˇˇˇˇˇ®(œ1
  615. .°dONLNdaŸäÂë(‚äYï°dONLNdbŸêÂ)ou can determine whether the ï°dONLNdŸÂ=)âFSSpecï°dONLNdÖŸ=ÂC)$ rg`°dONLNdáŸCÂo)
  616. outines ar9¿°dONLNdëŸoÂÁ),e available by calling the 9¿°dONLNd¨ŸÁÂ)xGestalt9¿°dONLNd≥ŸÂ)* °dONLNd¥ÂäÒ€(Óäfunction with the °dONLNdΔ€Ò))QgestaltFSAttr°dONLNd”Â)Ò¥)N" selector code, as illustrated in °dONLNdıÂ¥Ò‰)ã Listing 1-2°dONLNd‰ÒÁ)0.ˇ∂@ˇ ˇˇˇˇ@
  617. ˇ·ˇ‚7^
  618. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  619. (‡*1 )-c)12    )9 Using Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯
  620. g*j¯4g*j¯"g*a
  621. ˇ·ˇ‚7^    °dONLNdˇˇ(dl Listing 1-2°dONLNd\∞gµ)DT°dONLNd\µgs)2esting for the availability of the FSSpec routines,
  622. Courier
  623. .°dONLNd4slP(|l&FUNCTION FSSpecRoutinesAvail: Boolean;°dONLNd[Ålç~*VAR°dONLNdcè~õ¢+myErr:°dONLNdnèÿõ¸)ZOSErr;°dONLNdxè õû)H{Gestalt result code}°dONLNdíù~©∫(¶~
  624. myFeature:°dONLNd°ùÿ©)ZLongInt;°dONLNd≠ù ©å)H{Gestalt response}°dONLNd¿´l∑ä(¥lBEGIN°dONLNd π~≈,+FSSpecRoutinesAvail := FALSE;°dONLNdÌ«~”Ñ*m°dONLNdÓ«Ñ”Ä)*yErr := Gestalt(gestaltFSAttr, myFeature);°dONLNd’~·Ñ(fi~I°dONLNd’Ñ·¸)F myErr <> noErr THE°dONLNd3’¸·)xN°dONLNd:„êÔñ(ÏêD°dONLNd;„ñÔfi) oError(myErr°dONLNdG„fiÔ‰)H)°dONLNdMÒ~˝Ñ(˙~E°dONLNdNÒÑ˝ê)LS°dONLNdPÒê˝ñ) E°dONLNdWˇê ñ*I°dONLNdXˇñ û),F BTst(myFeature, gestaltHasFSSpecCalls) THE°dONLNdÑˇû §(ûN°dONLNd墮(¢F°dONLNdç®D)SSpecRoutinesAvail := TRUE°dONLNdßDJ)ú;°dONLNd©l'~($lEND°dONLNd¨~'Ñ);.°dONLNdÆ3l?r(<lTµ¿°dONLNdØ3q?§) o use the pr]İdONLNdª3•?√)4ocedurÙ¿°dONLNd¡3√?fl)es defimİdONLNd»3‡?µ)0ned in the following sections to open and save fiņ°dONLNd˘3µ?Ì)’les, you also .°dONLNd?lK∂(Hlneed to make surR`°dONLNd?∂KÍ)J e that the r$¿°dONLNd#?ÍK )4outines $¿°dONLNd+? Kf)"StandardGetFile$¿°dONLNd:?fK{)Z and $¿°dONLNd??{K’)StandardPutFile$¿°dONLNdN?’K·)Z ar˜ °dONLNdQ?‡KÁ) e °dONLNdSKlWü(Tl available. R`°dONLNd^KüW¶)3Yg`°dONLNd_K•W)ou can do this by passing g`°dONLNdyKW?)pGestaltg`°dONLNdÄK?WS)* the g`°dONLNdÖKSW›)gestaltStandardFileAttrg`°dONLNdúK›Wfl)ä °dONLNdùWlc    (`l$selector and verifying that the bit °dONLNd¡W    cá)ùgestaltStandardFile58°dONLNd÷Wác√)~ is set in the rR`°dONLNdÊW√cÁ)<esponse °dONLNdÓcloã(llvalue. !†°dONLNdıcãoº) Also, beforÙ°dONLNdcªoÌ)0 e using the Ù°dONLNd cÌo))2
  625. FindFolderÙ°dONLNdc)o…)<% function (as shown, for example, in Ù°dONLNd;c…oÙ)†
  626. Listing 1-°dONLNdEol{q(xl8°dONLNdFoq{¡)), you should call °dONLNdYo¡{Î)PGestalt°dONLNd`oÎ{)*
  627.  with the °dONLNdjo{ñ)-gestaltFindFolderAttr°dONLNdoñ{Ô)~ selector and verify ˇˇ—t°dONLNdî{láî(Ñl    that the ˇˇt\"˰dONLNdù{ïá%))gestaltFindFolderPresentˇˇ—t"˰dONLNdµ{%á∫)ê% bit is set; this indicates that the ˇˇt\Æà°dONLNd⁄{∫áˆ)ï
  628. FindFolderˇˇ—tÆà°dONLNd‰{ˆá˜)< .°dONLNdÂálì«(êlfunction is available..°dONLNd¸ôl•å*If the rR`°dONLNdô啈) outines that operate on R`°dONLNdôˆ•)jFSSpecR`°dONLNd"ô• )$ r$¿°dONLNd$ô •2)ecor˜ °dONLNd(ô1•G)ds ar…İdONLNd-ôG•ƒ)e not available, you can use .°dONLNdJ•l±}(Ælcorr`°dONLNdN•~±!)"esponding File Manager and StandarÆÄ°dONLNdp•!±g)£d File Package röİdONLNdÄ•g±‰)Foutines. For example, if you .°dONLNdù±lΩü(∫l cannot call °dONLNd©±üΩ’)3    FSpOpenDFï°dONLNd≤±‘Ω)5, you can call ï°dONLNd¡±Ω:)<HOpenDF™°dONLNd»±9Ωµ)). That is, instead of writing°dONLNdÊ…l’Ä(“l.myErr := FSpOpenDF(mySpec, fsCurPerm, myFile);.°dONLNd·lÌÏ*you can write something like.°dONLNd2˘l‘*<myErr := HOpenDF(myVol, myDirID, myName, fsCurPerm, myFile);°dONLNdol§* The only difR`°dONLNd{§±)8fer$¿°dONLNd~±˘)ence is that the $¿°dONLNdè˘)HFSSpec$¿°dONLNdï_)$ parameter is r˜ °dONLNd§^†)Aeplaced by thr…İdONLNd≤†‚)Bee parameters .°dONLNd¿l)‘(&lspecifying the volume rÿİdONLNd◊‘)‰)heferц°dONLNd€Â)) ence number İdONLNdÊ)B)9    , the par1°dONLNdÔB)_)$ent dirWİdONLNdˆ_)∂)ectory ID, and the fi>°dONLNd ∑)Ê)X    lename. W“`°dONLNdÂ)Û).ith °dONLNd)l55(2l/only a few exceptions, all of the techniques pr¸†°dONLNdG)55’)…&esented in this chapter can be easily .°dONLNdm5lA"(>l%adapted to work with high-level HFS rR`°dONLNdí5"Aá)∂outines in place of the R`°dONLNd™5áA´)eFSSpecR`°dONLNd∞5´A±)$ r$¿°dONLNd≤5±A‘)outines.ˇV@ˇ ˇˇˇˇ@
  629. ˇ·ˇ‚7^
  630. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä Using Files
  631. ~¿(‡1‡)-a¿)13(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿
  632. ^Hj4^Hj°dONLNdˇˇ(eäNOTE
  633. ˇ·ˇ‚7^
  634. °dONLNdgäsK* *One notable exception concerns the Standar›@°dONLNd*gKs∏)¡d File Package functions ,
  635. Courier.°dONLNdCsä¿(|ä    SFGetFile°dONLNdLs¿’)6 and °dONLNdQs’ )    SFPutFile°dONLNdZs $)6. The °dONLNd`s$N)vRefNum°dONLNdgsNT)* fPİdONLNdisTä)ield of the r"‡°dONLNdvsä•)6eply rı@°dONLNd|s§∂)ecor«†°dONLNdÄs∂æ)d .°dONLNdÇäã@(àä*passed to both these functions contains a I¿°dONLNd¨Aãï)∑working directory °dONLNdæãäó⁄(îäreference numberƒ¿°dONLNdŒã⁄ó‹)P,D¿°dONLNdœã›ó°), which is a number that encodes both the dir›Ä°dONLNd˚ã°óæ)ƒectory °dONLNdó䣄(†äID and the volume r‘ °dONLNdó„£Û)YeferÄ@°dONLNdóÙ£-) ence number °dONLNd$ó-£≥)9. In general, you should avoid °dONLNdC£äØ{(¨ä8using this number; instead you can turn it into the corrG°dONLNd{£|Ø≠)Ú
  636. esponding .°dONLNdÖØäªò(∏ädirR`°dONLNdàØòª˛)ectory ID and volume r$¿°dONLNdûØ˛ª)fefer˜ °dONLNd¢Øªá)ence number by calling the ˜ °dONLNdΩØáªΩ)x    GetWDInfo˜ °dONLNdΔØΩªø)6 .°dONLNd«ªä«˘(ƒäfunction. See the chapter °dONLNd·ª˙«ˇ)p“°dONLNd‚ªˇ«L)The File Managerx@°dONLNdÚªL«Q)M”x@°dONLNdÛªQ«§) in this volume for °dONLNd«ä”Ï(–ädetails on working dir‹†°dONLNd«Ï”)bectory rï °dONLNd%«”)"eferA@°dONLNd)«”_)ence numbers.,Zapf DingbatsCİdONLNdˇˇ)Cu
  637. ˘Hˇ4˘H˛ ˘ä˘
  638. ˇ·ˇ‚7^ˇˇ◊ˇ◊°dONLNdKÁä¯ß(ÙäDefiø@°dONLNdOÁ߯J)ning a Document Recor˙ê°dONLNddÁJ¯S)£dˇˇˇˇˇˇ®)ƒ1
  639. °dONLNdf˛ä
  640. Ã(äWhen a user cr¢°dONLNdt˛Ã
  641.     )BEeates a new document or opens an existing document, your application °dONLNdπ
  642. äk(ä1displays the contents of the document in a windowëİdONLNdÍ
  643. kó)·
  644. , which pr+°dONLNdÙ
  645. ò‡)-ovides a standarɰdONLNd
  646. ‡)H d interface °dONLNdä"(ä\for the user to view and possibly edit the document data. It is useful for your application °dONLNdl"ä.¶* to defi™°dONLNds"¶.∫)ne a E°dONLNdx"ª.
  647. )document record,±Ä°dONLNdà"
  648. .k)O an application-specifi˚¿°dONLNdü"k.ì)a
  649. c data str( °dONLNd©"î.´))ucturưdONLNdÆ"´.Ì)e that contains °dONLNdæ.ä:(7äinformation about the windowÌ`°dONLNd⁄.:?)á , any contrå`°dONLNdÂ.@:ƒ)/ols in the window (such as scr@@°dONLNd.≈:)Öoll bars), and the °dONLNd:äFê(Cäfiå¿°dONLNd:êF )le (if any) whose contents arưdONLNd5: FÅ)|e displayed in the windowèİdONLNdN:ÅFÜ)u. èİdONLNdP:ÜF¥) Listing 1-3/¿°dONLNd[:µF)/ illustrates a sample °dONLNdqFäRΩ(Oä
  650. document r°dONLNd{FΩRœ)3ecorÛ`°dONLNdFœRz)(d for an application that handles text fiZ¿°dONLNd®F{Râ)¨les.
  651. uHx4uHx"uHa
  652. ˇ·ˇ‚7^    °dONLNdˇˇ(rä Listing 1-3°dONLNd≠jŒu‘)DA0°dONLNdÆj‘u9) sample document record
  653. .°dONLNdΔÇäé¢(ãäTYPE°dONLNdœêúúfi+ MyDocRecHnd°dONLNdflêˆúP)Z= ^MyDocRecPtr;°dONLNdÛûú™fi(ßú MyDocRecPtr°dONLNdûˆ™>)Z = ^MyDocRec;°dONLNd¨ú∏Ã(µúMyDocRec°dONLNd!¨ˆ∏¸)Z=°dONLNd'∫úΔ¿(√úRECORD°dONLNd3»Æ‘fi+editRec:°dONLNd@»‘>)Z    TEHandle;°dONLNdO»t‘)l{handle to TextEdit record}°dONLNdp÷Æ‚(flÆ vScrollBar:°dONLNdÄ÷‚\)ZControlHandle;°dONLNdî÷t‚Ú)l{vertical scroll bar}°dONLNd؉Æ(ÌÆ hScrollBar:°dONLNdø‰\)ZControlHandle;°dONLNd”‰t˛)l{horizontal scroll bar}°dONLNdÚÆ˛(˚Æ fileRefNum:°dONLNdÚ˛8)ZInteger;°dONLNdÚt˛)l{ref num for window’s file}°dONLNd/Æ (    Æ fileFSSpec:°dONLNd? 2)ZFSSpec;°dONLNdLt Œ)l{file’s FSSpec}°dONLNdaƈ(Æ windowDirty:°dONLNdr2)ZBoolean°dONLNdt)l{has window data changed?}°dONLNdûú(¥(%úEND;°dONLNd£4ä@û(=äThe °dONLNdß4û@Œ)MyDocRec°dONLNdØ4Œ@-)0 data type contains fi°dONLNd≈4-@º)_ elds for information about the Tï°dONLNdÂ4ª@„)é    extEdit rg`°dONLNdÓ4„@ı)(ecor9¿°dONLNdÚ4ı@)d that .°dONLNd˘@äLÃ(IäIcontains the window’s text data and about the horizontal and vertical scr⇰dONLNdB@ÃL
  654. (IÃoll bars in the °dONLNdRLäX(Uäwindow; it also contains a fi;†°dONLNdoLX;)|eld for the fi/İdONLNd}L<XJ)6le r&İdONLNdÅLJXZ)efer“†°dONLNdÖLZX–)ence number of the open fifi°dONLNdüL–X¸)v le (if any) °dONLNd´Xäd?(aä&whose data the window displays and a fi †°dONLNd“X?dt)µeld for the fiæÄ°dONLNd‡XudΩ)6le system specifi«¿°dONLNdÒXΩdÓ)H cation that °dONLNd˝däp©(mäidentifiV†°dONLNdd™pœ)     es that fi¿ °dONLNddœpÙ)%    le. The fi∫†°dONLNddıp)&le r±†°dONLNddp)efer]¿°dONLNd!dp)4ence number is needed when the application wants to .°dONLNdUpä|é(yärR`°dONLNdVpé|Á)ead or write data fr$¿°dONLNdjpÁ|)Yom the fi$¿°dONLNdsp|Ä)(le, as well as when the fi$¿°dONLNdçpÄ|·)qle is to be closed. The $¿°dONLNd•p·|)aFSSpec$¿°dONLNd´p|)$ .°dONLNd¨|äàç(ÖärE°dONLNd≠|éà†)ecorπ`°dONLNd±|†à´)d i=İdONLNd¥|¨àÔ) Gs needed when the application wants to save any changed data into the fif@°dONLNd¸|Ôà(ÖÔ    le using °dONLNd    àäî–(ëäa “safe-save” pr¢`°dONLNd    à–îÓ)Focedur9†°dONLNd    àÔîˆ)e.ˇˇ†.°dONLNd    öä¶∏(£ä
  655. The last fi¿°dONLNd    )ö∏¶‰). eld of the ˇ˛‡†°dONLNd    4ö¶)-MyDocRecˇˇ††°dONLNd    <ö¶)09 data type is a Boolean value that indicates whether the .°dONLNd    u¶ä≤(Øä!contents of the document in the T¡Ä°dONLNd    ñ¶≤C)ì    extEdit rù`°dONLNd    ü¶C≤U)&ecor¿°dONLNd    £¶V≤j)d dif◊‡°dONLNd    ®¶j≤)fer frć°dONLNd    Æ¶Ä≤) om the contents of the document °dONLNd    Œ≤俀(ªäin the associated fi¿°dONLNd    ‚≤‹æW)Rle. When your application fit °dONLNd    ˛≤Wæh){rst r+ °dONLNd
  656. ≤iæç)eads a fiZ@°dONLNd
  657. ≤çæ‡)$le into the windowÈ@°dONLNd
  658. ≤flæ¸)R, this fiØ °dONLNd
  659. '≤˝æ)eld ˇ<@ˇ ˇˇˇˇ@
  660. ˇ·ˇ‚7^
  661. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  662. (‡*1 )-c)14    )9 Using Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯
  663. °dONLNd\lhπ(elshould be set to F3°dONLNd\πhÒ)MEALSE. Then, when any subsequent operations alter the contents of the °dONLNdWhlt˜(qldocument, you should set the fi°dONLNdvh¯t3)åeld to TRUE. ¿°dONLNdÉh3t9);Y“@°dONLNdÑh8t )"our application can inspect this fiu°dONLNdßhÀt€)ìeld °dONLNd´tlÄØ(}lwhenever appr∏¿°dONLNd∏tØÄ?)C"opriate to determine if special pr◊¿°dONLNd⁄t?ÄÌ)ê&ocessing is needed. For example, when .°dONLNdÄlå-(âl*the user closes a document window and the ,
  664. Courier°dONLNd*Ä-åo)¡ windowDirty°dONLNd5Äoåx)B fl°dONLNd8Äxå≈)    ag is TRUE, your .°dONLNdIålòÙ(ïlVapplication should ask the user whether the changed version of the document should be °dONLNdüòl§©* saved in the filİdONLNdÆò™§»)>le. See qİdONLNd∂ò»§˚) Listing 1-14¿°dONLNd¬ò¸§-)4 for details.°dONLNd–™l∂r(≥lTµ¿°dONLNd—™q∂›)o associate a document r˛`°dONLNdÈ™›∂Ô)lecorr¿°dONLNdÌ™∂i)d with a particular windowaİdONLNd™i∂ˆ)y!, you can simply set a handle to °dONLNd(∂l¬É(ølthat r °dONLNd.∂Ѭñ)ecorèİdONLNd2∂ñ¬æ)
  665. d as the r
  666. †°dONLNd<∂ø¬œ))efer∂¿°dONLNd@∂œ¬ñ)+ence constant of the window (by using the Wæ°dONLNdk∂ñ¬fl)«indow Manager .°dONLNdy¬lŒv(ÀlprR`°dONLNd{¬vŒì)
  667. ocedur$¿°dONLNdŬìŒö)e $¿°dONLNdɬöŒ÷)
  668. SetWRefCon$¿°dONLNdç¬÷Œ)<). Then you can r˜ °dONLNdû¬ŒÉ)Hetrieve the document r…İdONLNd¥¬ÉŒï)eecorõ‡°dONLNd∏¬ïŒfi)d by calling the °dONLNd…Œl⁄®(◊l
  669. GetWRefCon°dONLNd”Œ®⁄”)<  function. °dONLNdfiŒ”⁄)+ Listing 1-6°dONLNdÈŒ⁄V)0 illustrates this prR`°dONLNd˝ŒV⁄o)Socess.
  670. ˇ*¯4*¯ l¯
  671. ˇ·ˇ‚7^ˇˇ◊.ˇ◊°dONLNdÓlˇ}(˚lCrè °dONLNdÓ}ˇˆ)eating a New Fileˇˇˇˇˇˇ®(˚1
  672. °dONLNdl¯(l!The user expects to be able to crô†°dONLNd9¯Ê)å1eate a new document using the New command in the °dONLNdjlù(l File menu. ü†°dONLNduùÀ)1 Listing 1-5?‡°dONLNdÄÃ√)/4 illustrates one way to handle the New menu command.
  673. ?*C¯4@*B¯"@*a
  674. ˇ·ˇ‚7^    °dONLNdˇˇ(=l Listing 1-4°dONLNdµ5∞@:)DHandling the New menu command
  675. .°dONLNd”LlX(UlFUNCTION DoNewCmd: OSErr;°dONLNdÌZlf~*VAR°dONLNdıh~t¢+myWind°dONLNd˚h¢tÆ)$ow°dONLNd˝hÆt¥) :°dONLNdhΔt)
  676. WindowPtr;°dONLNdh t∂)Z{the new document window}°dONLNd/v~Ç®(~myData:°dONLNd:vΔÇ)H MyDocRecHnd;°dONLNdKv Çº)Z{the window’s data record}°dONLNdfÑlêä(çlCONST°dONLNdpí~ûÍ+rDocWindow = 1000;°dONLNdãí û‡)¢ {resource ID of window template}°dONLNd¨†l¨r(©lB°dONLNd≠†r¨ä)EGIN°dONLNd∂Æ~∫⁄+ :{allocate a new window; see Window Mgr chapter for details°dONLNdÆ⁄∫‡(∑⁄}°dONLNdˆº~»∫(≈~
  677. myWindow :°dONLNdº∫»‘)</= GetNewWindow(rDocWindow, NIL, WindowPtr(-1));°dONLNd4 ~÷Ñ(”~I°dONLNd5 Ñ÷Ã) F myWindow =°dONLNdA Ã÷)H     NIL THEN°dONLNdPÿê‰Æ(·êBEGIN°dONLNd\Ê¢Ú +DoNewCmd := MemError;°dONLNdxÙ¢¸*Exit(DoNewCmd);°dONLNdçê®( êEND;°dONLNdó~*å('~-{allocate space for the window’s data record}°dONLNd…,~8∞*3myData := MyDocRecHnd(NewHandle(SizeOf(MyDocRec)));°dONLNd:~Fˆ*IF myData = NIL THEN°dONLNdHêTÆ+BEGIN°dONLNd'V¢b +DoNewCmd := MemError;°dONLNdCd¢p2*DisposeWindow(myWindow);°dONLNdbr¢~®*E°dONLNdcr®~¸)xit(DoNewCmd);°dONLNdwÄêå®(âêEND;°dONLNdÉú~®(•~HLock(Handle(myData));°dONLNd¶úh®Œ)Í{lock the handle}°dONLNdº™~∂fi(≥~WITH myData^^ DO°dONLNdŸ™h∂Ê)Í{fill in window data}ˇ*@ˇ ˇˇˇˇ@
  678. ˇ·ˇ‚7^
  679. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä Using Files
  680. ~¿(‡1‡)-a¿)15(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿,
  681. Courier
  682. .°dONLNd\ÆhÃ(eÆBEGIN°dONLNd j¿v§+&editRec := TENew(gDestRect, gViewRect)°dONLNd2j§v™)‰;°dONLNd:x¿ÑΔ(Å¿v°dONLNd;xΔѬ)*Scroll := GetNewControl(rVScroll, myWind);°dONLNdlÜ¿í¬(è¿+hScroll := GetNewControl(rHScroll, myWind);°dONLNdû *fileRefNum := 0;°dONLNdπî܆⁄)Δ{no file yet!}°dONLNdŒ¢¿Æ>(´¿windowDirty := FALSE;°dONLNdÓ∞¿º§*&IF (editRec = NIL) OR (vScroll = NIL) °dONLNdæ¿ J*OR (hScroll = NIL) THEN°dONLNd:Óÿ+BEGIN°dONLNdH⁄‰Êb+DoNewCmd := MemError;°dONLNdfˉÙt*DisposeWindow(myWindow);°dONLNdሉt*HUnlock(Handle(myData));°dONLNd®‰b*DisposHandle(myData);°dONLNdΔ‰t*DisposeControl(vScroll);°dONLNdÁ ‰,t*DisposeControl(hScroll);°dONLNd.‰:V*TEDispose(editRec);°dONLNd$<‰H>*Exit(DoNewCmd);°dONLNd;J“VÍ(S“END;°dONLNdEXÆdΔ(aÆEND;°dONLNdOtúÄÿ(}ú
  683. SetWRefCon°dONLNdYtÿÄ)<
  684. (myWindow,°dONLNdctÄÄ)< LongInt(myData));°dONLNdÇtÜÄ)r{link record to window}°dONLNdûÇúé,(ãúHUnlock(Handle(myData));°dONLNd√ÇÜé¯)Í{unlock the handle}°dONLNd€êúú(ôúDoNewCmd := noErr;°dONLNdÓû䙢(ßäEND;ˇˇ∑b°dONLNdÛ∂ä¬À*Note that the ˇˇ&&¶&°dONLNd∂À¬˚)ADoNewCmdˇˇ∑b¶&°dONLNd    ∂˚¬x)0 function does not actually crp°dONLNd'∂y¬±)~ eate a new fi3ñ°dONLNd4∂±¬)8le. This is because it is .°dONLNdN¬äŒ—(ÀäJusually better to wait until the user chooses to save a new document befor°°dONLNdò¬—Œ‡(À—e cr‡°dONLNdú¬·Œ)    eating a .°dONLNd•Œä⁄ë(◊äfi°dONLNdߌë⁄œ)Fle (mainly because the user might not want to save the document). The °dONLNdÌŒœ⁄ˇ(◊œDoNewCmd°dONLNdıŒˇ⁄)0 .°dONLNdˆ⁄äÊπ(„ä function crCİdONLNd⁄∫Êˇ)0eates a windowd °dONLNd⁄˛Ê{)D, allocates a new document r‘†°dONLNd+⁄{Êç)}ecorI°dONLNd/⁄éÊ≤)d, and fifi†°dONLNd8⁄≤ÊÊ)$lls out the fiİdONLNdF⁄ÁÊ)5elds of .°dONLNdNÊäÚ•(Ôäthat rR`°dONLNdTÊ•Ú∑)ecor$¿°dONLNdXÊ∑ÚÏ)
  685. d. Howeverg`°dONLNdbÊÎÚ)4, it sets the g`°dONLNdpÊÚ[)4
  686. fileRefNumg`°dONLNdzÊ[Úd)< fig`°dONLNd}ÊdÚ¬)    eld of the document r9¿°dONLNdíʬڑ)^ecor  °dONLNdñÊ‘Ú˘)
  687. d to 0 to .°dONLNd†Úä˛◊(˚äindicate that no fi„‡°dONLNd≥Ú◊˛˝)M
  688. le is currÍ@°dONLNdΩÚ˝˛î)&!ently associated with this windowI@°dONLNdfiÚî˛ô)ó. 
  689. #H)4$H) $ä$
  690. ˇ·ˇ‚7^ˇˇ◊ˇ◊°dONLNd·ä#Ô(äOpening a Fileˇˇˇˇˇˇ®(1
  691. °dONLNd)ä5ê(2äY@İdONLNdÒ)ê5<)&our application might need to open a fiùİdONLNd)<5)¨le in several dif °dONLNd))Ä5å)DferÁ†°dONLNd,)ã5)  ent situations. For example, if °dONLNdL5äA(>äWthe user launches your application by double-clicking one of its document icons in the °dONLNd£AäMß* Finder„İdONLNd©A¶M‰), the Finder pr®‡°dONLNd∏AÂMˆ)?=ovides your application with information about the selected fiİdONLNdˆA˜M(J˜le (if °dONLNd˝MäYŸ(Väyour application r˙@°dONLNdMŸY˝)OAeceives high-level events, the Finder sends it an Open Documents °dONLNdPYäe™(bäevent). ¬¿°dONLNdXY™e') At that point, you want to cry‡°dONLNduY(eÊ)~(eate a new window for the document and r@°dONLNdùYÁe    )øead the °dONLNd•eäq÷(nädocument data fr±°dONLNdµe÷q˝)Lom the fi‰†°dONLNdæe˝qP)'le into the windows†°dONLNd–ePqR)S.°dONLNd“wäÉê(ÄäY@İdONLNd”wêÉ)our application also opens fi]‡°dONLNdwÉ*)}les in rÀ†°dONLNd¯w*É)2esponse to the user selecting the Open command in °dONLNd*Éäèã(åä:the File menu. In this case, you need to determine which fi;`°dONLNdeÉåèº(åå le to open. ä@°dONLNdqɺè¬)0YJ¿°dONLNdrɬè)ou can use the °dONLNdÅèäõ¨(òäStandar¥@°dONLNdàè¨õ)"d File Package to pr⁄@°dONLNdúèõE)Wesent a standarÔ¿°dONLNd´èEõ )B.d dialog box that allows the user to navigate °dONLNdŸõä߆(§äthe fiÍ °dONLNdflõ†ßÊ)le system hierar¿@°dONLNdÔõÊßp)F!chy (if necessary) and select a fi™¿°dONLNdõqß´)ãle of the apprL¿°dONLNdõ¨ß);opriate type. Once you °dONLNd6ßä≥(∞ä get the necessary information frù`°dONLNdVß≥Y)åom the Standar¯Ä°dONLNddßY≥·)Cd File Package, you can then crP‡°dONLNdÉß‚≥)â eate a new °dONLNdé≥äø(ºäwindow for the document and r˛Ä°dONLNd´≥øÜ)çead the document data frÚ@°dONLNd√≥Üø≠)oom the fi%‡°dONLNdÃ≥Æø)(le into the window¥‡°dONLNdfi≥ø)R.ˇ¸@ˇ ˇˇˇˇ@
  692. ˇ·ˇ‚7^
  693. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  694. (‡*1 )-c)16    )9 Using Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯
  695. °dONLNd\lh9(el/As you can see, it makes sense to divide the priİdONLNd/\9hÒ)Õ)ocess of opening a document into several °dONLNdXhltx(qldif™`°dONLNd[hxtÑ) fer凰dONLNd^hÑtò) ent rØ@°dONLNdchòtΩ)    outines. °dONLNdlhætƒ)&Y¡Ä°dONLNdmh√t)ou can have a rܰdONLNd|htb)Coutine that elicits a fiù†°dONLNdîhbtú)\le selection fr°dONLNd£hùtÁ);om the user and °dONLNd≥tlÄî(}l    another r€‡°dONLNdºtîÄŒ)(outine that cr©†°dONLNd tœÄ-);eates a window and rg`°dONLNdfit.Ä[)_
  696. eads the fis‡°dONLNdÈt[Äÿ)-le data into it. In the sample .°dONLNdÄlåª(âllistings given herR`°dONLNdĪå˝)Oe, the function ,
  697. CourierR`°dONLNd*Ä˝å3)B    DoOpenCmdR`°dONLNd3Ä3åÙ)6+ handles the interaction with the user and °dONLNd^ålò®(ïl
  698. DoOpenFile°dONLNdhå®òÆ)< rR`°dONLNdjåÆò—)eads a f"‡°dONLNdrå—ò4)#ile into a new window7‡°dONLNdáå3ò6)b..°dONLNdâûl™ö(ßl Listing 1-5 @°dONLNdîûõ™Ê)/H shows one way to handle the Open command in the File menu. It uses the .°dONLNd‹™l∂ë(≥lStandarR`°dONLNd„™ë∂⁄)%d File Package r$¿°dONLNdÛ™⁄∂¯)Ioutine $¿°dONLNd˙™¯∂R)StandardGetFile$¿°dONLNd    ™R∂∂)Z to determine which fi$¿°dONLNd™∂∂Á)d le the user .°dONLNd+∂l¬¨(ølwants to open.
  699. ‰*˯4Â*Á¯"Â*a
  700. ˇ·ˇ‚7^    °dONLNdˇˇ*# Listing 1-5°dONLNd:⁄∞Â>)DHandling the Open menu command
  701. .°dONLNdYÒl˝(˙lFUNCTION DoOpenCmd: OSErr;°dONLNdtˇl ~*VAR°dONLNd|~Æ+myReply:°dONLNdàΔ2)HStandardFileReply;°dONLNd°DÏ)~{Standard File reply record}°dONLNd√~'Æ($~myTypes:°dONLNdœΔ')H SFTypeList;°dONLNd·D'Ê)~{types of files to display}°dONLNd)~5¢(2~myErr:°dONLNd )Δ5Í)HOSErr;°dONLNd7lCä(@lBEGIN°dONLNdE~Qÿ+myErr := noErr;°dONLNd1S~_¸*myTypes[0] := 'TEXT';°dONLNdQSD_⁄)Δ{display text files only}°dONLNdpa~mz(j~*StandardGetFile(NIL, 1, myTypes, myReply);°dONLNd†o~{*IF myReply.sfGood THEN°dONLNdΩ}êâ\+"myErr := DoOpenFile(myReply.sfFile°dONLNdfl}\âb)Ã)°dONLNdÂã~óñ(î~ELSE°dONLNdÔôê•&+myErr := userCanceledErr;°dONLNdß~≥(∞~DoOpenCmd := myErr;°dONLNd"µl¡x(ælEN°dONLNd$µx¡Ñ) D;°dONLNd'ÕlŸÄ(÷lThe °dONLNd+ÕÄŸ⁄)StandardGetFile°dONLNd:Õ⁄ŸÊ)Z prR`°dONLNd=ÕÊŸ) ocedur$¿°dONLNdCÕŸ)e r˜ °dONLNdFÕŸ$)
  702. equir…İdONLNdKÕ$Ÿ[)es a list of fi…İdONLNdZÕ[ŸÔ)7"le types to display in the dialog .°dONLNd|ŸlÂÈ(‚lbox it puts up, illustrated in ˆ °dONLNdõŸÈÂ)}Figur»‡°dONLNd†ŸÂ)e 1-6f`°dONLNd•ŸÂÄ). In this case, only text fià`°dONLNd¡ŸÄÂó)jles arº`°dONLNd«Ÿó—)e to be listed.
  703.     *¯4    *¯"    *_
  704. ˇ·ˇ‚7^    °dONLNdˇˇ(l
  705. Figure 1-6.°dONLNd◊˛Æ    )BThe default Open dialog box
  706. lò¯4ló¯
  707. mêWò.∂n∂nmêW’ˇ¸’’÷ˇ‰÷ˇ‰`÷d`÷d`÷d`÷d`÷d`÷d`÷d`÷d`÷d`˘ˆˇ˛Îd`˘ˆÎd`˘ˇ¯Îd`˘ĢÎd`˘ɇ˝Îd"`˘ˇÉ0˝˜IJ|¿˛d#`˘ ™É1·Δgè˜IJf¿˛d%`˘ UÉ33&√ôġ„˘ˇ¡Éœ¯ffiyÁÄd%`˘ ™É33áÉôÄ√˘!ÜlÕfÊû¿d%`˘ UÉ3Ò«ôÄ?ɢ!Ülï|Δë¿d%`˘ ™É3ÁÉôĢ!ÜlÕò`Δ¸Ã¿d%`˘ UÉ3f√ôĢ!ÜlÕò`Δ¿Ã¿d%`˘ ™É··Δaè˘ˇ¡ÜlÕò`ΔƒÃ¿d `˘ˇ˚˜ ÛÃï`Δxg¿d`˘˘Îd`˘ˆÎd`˘ˆÎd`˘ıˇÎd`˘ıˇÎd`÷d`÷d`÷d`÷d`?ÁˇÛd`?Èˇ¯Ûd`?Èˇ¯Ûd`?Èˇ¯˘ˇ˛d`?ˇˇü˝ˇ¸ˇÁÙˇ¯$˘Äd`<ü˝ˇ3ˇˇÁÙˇ¯B¯Äd `;ˇ˜üáx3$·√áıˇ¯Å ¯@d `;ˇ˜ü337?3ÃÁsıˇ˘ê ¯@d&`:ˇ˜ü338?<ÃÁÉıˇ˚√– *Ä@d&`;ˇ˜ü˛3??<¿Á3ıˇ ¯B ˛@d&`<ü˛3??<œÁ3ıˇ¯B  †¢Ä@d%`?ˇˇü˛3??<ŒÁ3ıˇ¯B ˛˛@d&`?ˇˇÉá38??<·ÛÉıˇ¯~ (àÄÄ@d`?Èˇ ¯ Q˛@d`?Èˇ    ¯  ˛Ä@d`?Áˇ     ˛@d`?Èˇ¯ *††Ä@d` È ˛¸@d`!ˇÄΠ˛à¸@d`"E@Π˛P¸@d`"E 8Ä `Û¯Äd`"A d ¿`Û˘Äd `"> `x¯ «èåÒ‡Ù˘ˇ˛d    `" påà ˛Ãc0ÙÛd`" 8|ÃåÃÃc0ÙÛd`"> Ãà œÃÃc0ÙÛd`"A  Ãà à Ãc0ÙÛd`"A LÃà ÃLÃc0ÙÛd`"A 8|ÃáåÃ1‡ÙÛd`!ˇ‡ÎÛd` ÈÛd` È˘ˇ˛d` È˘Äd` È¯Äd` È ¯@d` ~Í ¯@d%    ` C<`˝Äı  ®ÄIJ@d%    ` CÄf`˝Äı  D@˛@d'` @Äf8Ò„·„`pÒ舠à( à¢ÇÄ@d'` @Äfdc˛3Ä…ôôˆ DDADD@@d'` @Äf`c˛3‡˘ôúˆ àà††Ç" @d'` @Äf`c33Ûqôü鈠DTQ@DD@@d'` @Äf`c339ôòˆ àÄ(†Ç" @d'` @Äfdc33ôôò술DDDD@@d'` Ä<81„·„p˘èˆ ®( à"ÇÄ@d` È ˚@d` È ˚@d` È ¯@d` È¯Äd` È˘Äd` È˘ˇ˛d` ~ÍÛd ` C8`0˝˜Ûd ` CÄd`0˝˜Ûd` @Ä`x¯Ò„˛>6‡˘Ûd    ` @ÄpÃÃc˝38 ëôôê˘Ûd    ` @Ä8ÃÃc˝30ôô¿˘Ûd` @ĸÃcÛ33?0ô¯‡˘Ûd` @Ä ¿Ãc3300ôôÄp˘Ûd` @ÄLƒÃc3310    ôôâ0˘Ûd` Ä8x¯1„3>0ò‡˘Ûd` ˝¿ÓÛd` ˝¿Ó˜U@d` ÈÛd` ÈÛd` 
  708. ÍÛd` U@ÎÛd` ™†ÎÛd    ` @TÔÛd    ` (ÔÛd
  709. ` @QAE@Ûd
  710. ` (¢"" Ûd
  711. ` @AQ@Ûd
  712. ` (Ç Ç Ûd
  713. ` @AD@Ûd
  714. `  Ç"" ˘ˇ˛d
  715. ` @AQD@˘Äd` È¯Äd` È ¯@d` È ¯@d` È ¿˛ @d` È  ˛ @d` È «√áå@d` È ffLÃ@d` È Êf Ã@d` È ffÃ@d` È ff @d` È &ffLL@d` È √Êcáå@d` È ¯@d` È ¯@d` È ¯@d` È¯Äd` È˘Äd` È˘ˇ˛d` ÈÛd` ÈÛd` ÈÛd` ÈÛd` ÈÛd` ÈÛd` ÈÛd` È¯ˇÄd` È¯ˇ‡d` È˜ˇd` È¯¯d` È«˘ˇ˛8d` Èÿ˘ºd` Èê¯úd` È†¯\d` È†¯\d` È†˚\d` È    †ĸ\d` È †ü˛\d` Èˇ†˛ôÄ\d` È†˛ôÄ\d` È†ôüôÄ\d` È~†ôòÄ\d` ÈB†ôòôÄ\d` ÈB†Ä\d` ÈB†˛¸\d` È √–†˛¸\d` È    ê†¯\d` ÈÅê¯úd` ÈBÿ˘ºd` È$«˘ˇ˛8d` È¯¯d` È˜ˇd` È¯ˇ‡d`?Áˇ¯ˇÄd`÷d`÷d`÷d`÷d`÷d`÷d`÷d`÷d`÷d`÷d÷ˇ‰÷ˇ‰’’’ˇ¸ˇÍ@ˇ ˇˇˇˇ@
  716. ˇ·ˇ‚7^
  717. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä Using Files
  718. ~¿(‡1‡)-a¿)17(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿
  719. °dONLNd\äh—(eäThe user can scrp°dONLNd\—hÎ)Goll thr°dONLNd\Ïh6)ough the list of fiÔ¿°dONLNd*\6hr)Jles in the curr$‡°dONLNd9\shê)=ent dirK`°dONLNd@\êh´)ectory£ °dONLNdF\™hÛ), change the curr@°dONLNdW\Ùh)Jent °dONLNd[hätñ(qädirI °dONLNd^hót≤)ectory†‡°dONLNddh±tfi) , select a fi‡°dONLNdqhflt£)..le to open, or cancel the operation altogetherÔ‡°dONLNdüh¢tÛ)√. When the user prÅ °dONLNd±hÙt )Resses .°dONLNd∑täÄ4(}ä&either the Cancel or the Open button, ,
  720. Courier°dONLNd›t4Äé)™StandardGetFile°dONLNdÏtéÄó)Z fi°dONLNdÔtóÄÏ)    lls out the StandarR`°dONLNdtÏÄ    )Ud File .°dONLNd    Ääåç(âärE°dONLNd
  721. Äéåß)eply rÕ@°dONLNdÄßåπ)ecorA†°dONLNdÄ∫åP)$d you pass to it, which has this str?¿°dONLNd8ÄPåg)ñuctur≈†°dONLNd=Ägån)e:.°dONLNd@òH§ÿ(°HTYPE StandardFileReply =°dONLNdZ¶T≤x+ RECORD°dONLNdc¥f¿ê+sfGood:°dONLNdo¥¿¿)ZBoolean;°dONLNd{¥¿∂)H{TRUE if user did not cancel}°dONLNdõ¬fŒÆ(Àf sfReplacing:°dONLNd¨¬¿Œ)ZBoolean;°dONLNd∏¬ŒÚ)H'{TRUE if replacing file with same name}°dONLNd‚–f‹ê(ŸfsfType:°dONLNdÓ–¿‹Í)ZOSType;°dONLNd˘–‹J)H {file type}°dONLNdfifÍê(ÁfsfFile:°dONLNdfi¿ÍÍ)ZFSSpec;°dONLNdfiÍb)H{selected item}°dONLNd0Ïf¯ú(ıf    sfScript:°dONLNd>Ï¿¯)Z ScriptCode;°dONLNdMϯ»)H {script of selected item’s name}°dONLNdp˙fñ(fsfFlags:°dONLNd}˙¿)ZInteger;°dONLNdâ˙\)H{Finder flags}°dONLNdöf®(f sfIsFolder:°dONLNd™¿)ZBoolean;°dONLNd∂™)H{selected item is a folder}°dONLNd‘f"®(f sfIsVolume:°dONLNd‰¿")ZBoolean;°dONLNd"™)H{selected item is a volume}°dONLNd$f0Æ(-f sfReserved1:°dONLNd$¿0)ZLongInt;°dONLNd+$0D)H
  722. {reserved}°dONLNd82f>Æ(;f sfReserved2:°dONLNdI2¿>)ZInteger;°dONLNdU2>D)H
  723. {reserved}°dONLNda@TLl(ITEND;°dONLNdfXädÓ+6In this situation, the rR`°dONLNd~XÓd)d    elevant fiR`°dONLNdàXdP),elds of the r$¿°dONLNdïXPdk)6eply r˜ °dONLNdõXjd|)ecor…İdONLNdüX|dé)d arõ‡°dONLNd£Xédß)e the õ‡°dONLNd©XßdÀ)sfGoodõ‡°dONLNdØXÀd‡)$ and õ‡°dONLNd¥X‡d)sfFileõ‡°dONLNd∫Xd)$ °dONLNdªdäpë(mäfi°dONLNdΩdëp)elds. If the user selects a fi°dONLNd€dpJ)wle to open, the °dONLNdÎdJpn)BsfGood°dONLNdÒdnpw)$ fi°dONLNdÙdwpÓ)    eld is set to TRUE and the °dONLNddÓp)wsfFile°dONLNddp)$ ˇˇ¯°dONLNdpä|ë(yäfi°dONLNdpë|’)eld contains an ˇˇË*h*°dONLNd(p÷|˙)EFSSpecˇˇ¯h*°dONLNd.p˙|ˇ)$ r2ò°dONLNd0p|)ecor¯°dONLNd4p|h)d for the selected fiÂ0°dONLNdIph|Ä)Vle. In ’L°dONLNdPpÅ|∞) Listing 1-5ÕZ°dONLNd[p±|À)0, the rè÷°dONLNdbpÃ|Ô)eturned ˇˇË*ተdONLNdjp|)$FSSpecˇˇ¯ተdONLNdpp|)$ °dONLNdq|äàé(ÖärR`°dONLNdr|éà†)ecor$¿°dONLNdv|†à·)d is passed dir˜ °dONLNdÖ|‡àb)@ectly to the application-defi˜ °dONLNd¢|bàö)Çned function ˜ °dONLNdØ|öà÷)8
  724. DoOpenFile˜ °dONLNdπ|÷à€)<. ˜ °dONLNdª|€à ) Listing 1-6˜ °dONLNdΔ| à)0 °dONLNd«àäî˜(ëäillustrates a way to defi°dONLNd‡à˜î)mne the °dONLNdÁàîQ)
  725. DoOpenFile°dONLNdÒàQîz)<
  726.  function.
  727. ∂H∫4∑Hπ"∑Ha
  728. ˇ·ˇ‚7^    .°dONLNdˇˇ(¥ä Listing 1-6°dONLNd¸¨Œ∑˛)D Opening a fiê°dONLNd¨ˇ∑)1le
  729. .°dONLNd √äœí(Ãä,FUNCTION DoOpenFile (mySpec: FSSpec): OSErr;°dONLNd9—ä›ú*VAR°dONLNdAflúο+myWind°dONLNdGfl¿ÎÃ)$ow°dONLNdIflÃΓ) :°dONLNdOflˆÎ,)*    WindowPtr°dONLNdXfl,Î2)6;°dONLNd`fltÎz)H{°dONLNdaflzί)window for file data}°dONLNd|Ìú˘Δ(ˆúmyData:°dONLNdà̈˘8)Z MyDocRecHnd°dONLNdìÌ8˘>)B;°dONLNdõÌt˘z)<{°dONLNdúÌz˘˛)handle to window data}°dONLNd¥˚ä¿(ä       myFile°dONLNdΩ˚¿‰)6RefNum°dONLNd√˚‰Í)$:°dONLNdÕ˚ˆ )Integer°dONLNd‘˚ &)*;°dONLNd‹˚tz)T{°dONLNd›˚z˛)file reference number}°dONLNd˘    ú¿(úmyErr:°dONLNd    ˆ)ZOSErr;°dONLNd ä#®( äBEGIN°dONLNd%ú1+myErr := DoNewCmd;°dONLNd4%t1Ú)ÿ{create a new window}°dONLNdN3ú? (<úIF myErr <> noErr THEN°dONLNdjAÆMÃ+BEGIN°dONLNdvO¿[8+DoOpenFile := myErr;°dONLNdë]¿i&*Exit(DoOpenFile);°dONLNd®kÆwΔ(tÆEND;°dONLNd≤áúìÿ(êú
  730. myWindow :°dONLNdºáÿì‰)<= °dONLNdæá‰ì&) FrontWindow°dONLNd…á&ì,)B;°dONLNd÷átìÊ)N{get window pointer°dONLNdÈáÊìÏ)r}°dONLNdÔïú° (ûúIF myWindow = NIL THEN°dONLNd £ÆØÃ+BEGIN°dONLNd±¿Ω8+DoOpenFile := myErr;ˇΔ@ˇ ˇˇˇˇ@
  731. ˇ·ˇ‚7^
  732. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  733. (‡*1 )-c)18    )9 Using Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯,
  734. Courier
  735. .°dONLNd\¢h(e¢Exit(DoOpenFile);°dONLNdjêv¢(sêEND°dONLNdj¢v®);°dONLNd!x~Ñ¥(Å~    SetWTitle°dONLNd*x¥Ñ)6
  736. (myWindow,°dONLNd4xÑD)< mySpec.name);°dONLNdNxVÑŒ)f{set window’s title}°dONLNdiî~†∞(ù~3{open the file’s data fork for reading and writing}°dONLNd°¢~Æ\*%myErr := FSpOpenDF(mySpec, fsRdWrPerm°dONLNdΔ¢\Æ∂)fi, myFileRefNum)°dONLNd’¢∂ƺ)Z;°dONLNd‹∞~º(π~IF myErr <> noErr THEN°dONLNd˙æê ®+BEGI°dONLNd˛æ® Æ)N°dONLNdâÿ2(’¢DisposeWindow(myWindow);°dONLNd%⁄¢Ê*DoOpenFile := myErr;°dONLNd@Ë¢Ù*Exit(DoOpenFile);°dONLNdWˆê¢(ˇêEND°dONLNd[ˆ¢®);°dONLNdb~t(~){retrieve handle to window’s data record}°dONLNdë ~,>* myData := MyDocRecHnd(GetWRefCon°dONLNd± >,z)¿
  737. (myWindow)°dONLNdª z,Ü)<);°dONLNd√.~:¸(7~myData^^.fileRefNum :°dONLNdÿ.¸:V)~= myFileRefNum;°dONLNdÛ.V:‡)Z{save file information}°dONLNd<~H2(E~myData^^.fileFSSpec := mySpec;°dONLNd<X~d*myErr := DoReadFile°dONLNdOXd,)r
  738. (myWindow)°dONLNdYX,d2)<;°dONLNdfXVd»)*{read in file data}°dONLNdf~rˆ(o~DoOpenFile := myErr;°dONLNdîtlÄÑ(}lEND;.°dONLNdôålò∂*This function is r °dONLNd´å∑ò_)K&elatively simple because much of the rŸÄ°dONLNd—å_ò€)®eal work is done by the two .°dONLNdÌòl§ñ(°l
  739. functions °dONLNd˜òñ§Δ)*DoNewCmd°dONLNdˇòΔ§€)0 and °dONLNdò€§)
  740. DoReadFile°dONLNdò§0)<. The °dONLNdò0§l)
  741. DoReadFile°dONLNdòl§¢)< function is rR`°dONLNd,ò¢§‚)6esponsible for .°dONLNd;§l∞ï(≠l
  742. actually rfi†°dONLNdE§ï∞Ã)) eading the fi˜°dONLNdR§Ã∞Û)7
  743. le data fr °dONLNd\§Ù∞T)(om the disk into the T‡°dONLNdr§T∞z)`    extEdit r˜¿°dONLNd{§y∞ã)%ecorl °dONLNd§å∞Î)d associated with the °dONLNdï∞lº¿(πldocument window»°dONLNd§∞øº)S. See the next section, ʇ°dONLNdº∞ºz)`“Reading File Data,”l@°dONLNd–∞{º«)\ for a sample defiflİdONLNd‚∞«ºÓ)L
  744. nition of .°dONLNdϺl»®(≈l
  745. DoReadFile°dONLNdˆº®»´)<.°dONLNd¯Œl⁄w(◊lIn °dONLNd˚Œw⁄ß) Listing 1-6°dONLNdŒß⁄!)0, the key step is the call to °dONLNd$Œ!⁄W)z    FSpOpenDFï°dONLNd-ŒV⁄Ú)5#, which opens the data fork of the .°dONLNdP⁄lÊà(„lspecifiÓ °dONLNdW⁄àÊõ)ed fi`@°dONLNd\⁄úÊ®)le. ≥‡°dONLNd`⁄®ÊØ) AÓİdONLNda⁄ØÊ∑) fi{@°dONLNdd⁄∏ÊΔ)    le rr@°dONLNdh⁄ΔÊ÷)efer`°dONLNdl⁄◊Ê›)8ence number—which indicates an access path to the open fiÌ °dONLNd•⁄›ÊÓ(„›le—°dONLNd®ÊlÚy(Ôlis rÍ`°dONLNd¨ÊyÚ…)eturned in the thir °dONLNdøÊ Ú)Q d parameterÓİdONLNd ÊˇÚ)5. ê °dONLNdÃÊÚa)As you can see, this r∞ °dONLNd‚ÊaÚq)]efer\@°dONLNdÊÊrÚÔ)ence number is saved in the .°dONLNdÚl˛ú(˚l
  746. document rR`°dONLNd Úú˛Æ)0ecor$¿°dONLNdÚÆ˛')d, whence it can easily be r˜ °dONLNd,Ú&˛t)xetrieved for futur…İdONLNd>Út˛∞)Ne calls to the …İdONLNdMÚ∞˛‘)<FSRead…İdONLNdSÚ‘˛È)$ and °dONLNdX˛l
  747. ñ(lFSWrite°dONLNd_˛ñ
  748. √)*  functions.°dONLNdkl(l&The second parameter in a call to the °dONLNdëK)©    FSpOpenDF°dONLNdöKë)6 function specifi°dONLNd´ëÙ)Fes the access mode for .°dONLNd¬l(©(%lopening the fi≈†°dONLNd–©(„)=le. For each fi܇°dONLNdfl‰();<le, the File Manager maintains access mode information that °dONLNd(l4(1lXdetermines what type of access is available. Most applications support one of two types °dONLNds4l@î*
  749. of access:,Zapf Dingbats°dONLNd~IlPq*n
  750. °dONLNdÄFxR) A∫†°dONLNdÅFRÚ) single user is allowed to r¿°dONLNdùFÛR )tead frñ°dONLNd£F Rb)om and write to a fiO@°dONLNd∑FcRm)Wle.°dONLNdª[lbq(aln
  751. °dONLNdΩXxd√) Multiple users arΔ°dONLNdŒX√dˇ)Ke allowed to r °dONLNd‹Xd)=ead frç`°dONLNd‚Xd7)om a fi„†°dONLNdÈX7d¥)le, but no one can write to it.°dONLNd    jlvr(slY@İdONLNd
  752. jrvŒ)Qour application can use the following constants to specify these types of access:ˇf@ˇ ˇˇˇˇ@
  753. ˇ·ˇ‚7^
  754. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä Using Files
  755. ~¿(‡1‡)-a¿)19(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿,
  756. Courier
  757. .°dONLNd\äh®(eäCONST°dONLNd
  758. \Æh‰)$    fsCurPerm°dONLNd\ˆh)H= 0;°dONLNd\h)$*{request exclusive read/write access; if }°dONLNdSjv*){ unavailable, request read-only access }°dONLNdÇxÆÑfi(ÅÆfsRdPerm°dONLNdéxˆÑ)H= 1;°dONLNdîxÑÏ)$#{request exclusive read permission}°dONLNdΩÜÆífi(èÆfsWrPerm°dONLNd…܈í)H= 2;°dONLNdœÜíÚ)$${request exclusive write permission}°dONLNd˘îƆÍ(ùÆ
  759. fsRdWrPerm°dONLNd)H= 3;°dONLNd)$%{request exclusive read/write access}°dONLNd3¨ä∏ê(µäTï°dONLNd4¨è∏º)
  760. o open a fiï°dONLNd?¨º∏)-le with exclusive rg`°dONLNdR¨∏ß)T"ead/write access, you can specify g`°dONLNdt¨ß∏„)ó
  761. fsRdWrPermg`°dONLNd~¨„∏Ó)<. T|`°dONLNdŨÌ∏)
  762.     o open a °dONLNdä∏äƒë(¡äfi°dONLNdå∏냆)le rR`°dONLNdê∏†ƒ…)ead-only6†°dONLNdò∏»ƒ)(
  763. , specify 6†°dONLNd¢∏ƒ )(fsRdPerm6†°dONLNd™∏ ƒã)0. If you want to open a fi6†°dONLNdƒ∏ãƒı)kle and don’t know or car    °dONLNd‹∏ıƒ¸)je ˇˇâÿ°dONLNdfiƒä–E(Õä+which type of access is available, specify ˇ˛ùàD˰dONLNd    ƒF–|)º    fsCurPermˇˇâÿD˰dONLNdƒ|–“)6. When you specify ˇ˛ùàlH°dONLNd%ƒ“–)V    fsCurPermˇˇâÿlH°dONLNd.ƒ–)6, if .°dONLNd3–䋟(Ÿäno access paths arLJ°dONLNdE–Ÿ‹Ï)Oe alry‡°dONLNdJ–Ï‹5)eady open, the fiΠ°dONLNd[–5‹≤)Ile is opened with exclusive r9‡°dONLNdx–≥‹ )~ead/write access. If °dONLNdç‹äËÂ(Âäother access paths arÅİdONLNd¢‹Â˯)[e alrxİdONLNdß‹¯Ë[)eady open, but they arÇ@°dONLNdΩ‹[Ëf)ce rꇰdONLNd¿‹fËå) ead-onlyl¿°dONLNd»‹åËπ)& , another r»†°dONLNd”‹πË)-ead-only path is °dONLNd‰ËäÙ@(Òä*opened. If an access path with exclusive r5 °dONLNdËAÙπ)∑ead/write permission is alrfiİdONLNd)ËπÙ)xeady open, the fiO¿°dONLNd:ËÙ)Jle °dONLNd=Ùä⁄(˝äcannot be opened.
  764. %H+4&H+ &ä&
  765. ˇ·ˇ‚7^ˇˇ◊ˇ◊°dONLNdOä%*$Reading File Dataˇˇˇˇˇˇ®(!1
  766. .°dONLNda+ä7ˇ(4äOnce you have opened a fi°dONLNdz+ˇ74)ule, you can rR`°dONLNdá+47g)5 ead data fr$¿°dONLNdí+g7¡)3om it by calling the $¿°dONLNdß+¡7Â)ZFSRead$¿°dONLNd≠+Â7)$  function. .°dONLNd∏7äCÚ(@äGenerally you need to r·@°dONLNdœ7ÚC!)h ead data fr=†°dONLNd⁄7"C@)0om a fi쇰dONLNd·7@Cë)le when the user fiÛ¿°dONLNdÙ7ëC…)Qrst opens a fiB °dONLNd7 C )9le or when the .°dONLNdCäO—(Läuser chooses to rR`°dONLNd"C—O≤)G3evert to the last saved version of a document. The R`°dONLNdUC≤OÓ)·
  767. DoReadFileR`°dONLNd_CÓO)< °dONLNd`Oä[¬(Xä function defi°dONLNdmO¬[fl)8ned in °dONLNdtOfl[) Listing 1-13°dONLNdÄO[y)5 illustrates how to use °dONLNdòOy[ù)eFSRead°dONLNdûOù[Æ)$ to rR`°dONLNd£OÆ[·) ead data fr$¿°dONLNdÆO·[ˇ)3om a fi$¿°dONLNdµOˇ[
  768. )le .°dONLNd∏[äg´(däinto a T'`°dONLNd¿[´g—)!    extEdit r@°dONLNd…[—g„)&ecorw†°dONLNdÕ[„gÈ)dì`°dONLNdŒ[Èg9) in either situation/†°dONLNd‚[:g<)Q.
  769. âHç4äHå"äHa
  770. ˇ·ˇ‚7^    °dONLNdˇˇ(áä Listing 1-7°dONLNd‰Œä&)DReading data from a fi‡°dONLNd˙'ä.)Yle
  771. .°dONLNd˝ñH¢¿(üHFUNCTION DoReadFile °dONLNdñ¿¢¸)x
  772. (myWindow:°dONLNdñ¸¢2)<     WindowPt°dONLNd$ñ2¢>)6r)°dONLNd&ñ>¢n) : OSErr;°dONLNd0§H∞Z(≠HVAR°dONLNd5≤Tæ~+ myData:°dONLNd@≤úæ‰)H MyDocRecHnd;°dONLNdT≤,æ⁄)ê{handle to a document record}°dONLNdt¿TÃ~(…TmyFile:°dONLNd¿úÃÃ)HInteger;°dONLNdè¿,Ã∂)ê{file reference number}°dONLNd®ŒT⁄x(◊TmyLeng°dONLNdÆŒx⁄ä)$th:°dONLNdµŒú⁄Ã)$LongInt;°dONLNd≈Œ,⁄˛)ê#{number of bytes to read from file}°dONLNdÍ‹TË~(ÂTmyText:°dONLNdı‹úË“)H    TEHandle;°dONLNd‹,ËŒ)ê{handle to TextEdit record}°dONLNd#ÍTˆx(ÛTmyBuff°dONLNd)Íxˆä)$er:°dONLNd0Íúˆ¥)$Ptr;°dONLNd<Í,ˆº)ê{pointer to data buffer}°dONLNdV¯Tx(TmyErr:°dONLNd`¯ú¿)HOSErr;°dONLNdgHf(HBEGIN°dONLNdnT +  myData := MyDocRecHnd(GetWRefCon°dONLNdé P)¿
  773. (myWindow)°dONLNdòP \)<);°dONLNd©b ‘){get window’s data}°dONLNd¿"T.(+TmyFile := myData^^.fileRefNum;°dONLNdÌ"b.(+b{get file reference number}°dONLNd
  774. 0T<J(9T)myErr := SetFPos(myFile, fsFromStart, 0);°dONLNdB0b<Ú(9b{set file mark at start}°dONLNd\>TJÿ(GTIF myErr <> noErr THEN°dONLNduLfXÑ+BEGIN°dONLNd~Zxf+DoReadFile := myErr;°dONLNdñhxtfi*Exit(DoReadFile);°dONLNd™vfÇ~(fEND;°dONLNd±íTû(õTmyErr := GetEOF(myFile, myLeng°dONLNdœíû)¥th°dONLNd—íû ) );°dONLNd‚íbû¬)N{get file length°dONLNdÚí¬û»)`}°dONLNdı†T¨(©TmyBuffer := NewPtr(myLength);°dONLNd!†b¨‘(©b{allocate a buffer}°dONLNd6ÆT∫ÿ(∑TIF myBuffer = NIL THENˇ  @ˇ ˇˇˇˇ@
  775. ˇ·ˇ‚7^
  776. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  777. (‡*1 )-c)20    )9 Using Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯,
  778. Courier
  779. .°dONLNd\Hhf(eHBEGIN°dONLNd    jZv‰+DoReadFile := MemError;°dONLNd$xZÑ¿*Exit(DoReadFile);°dONLNd8ÜHí`(èHEND;°dONLNd?¢6Æ<(´6m°dONLNd@¢<ÆÍ)yErr := FSRead(myFile, myLeng°dONLNd]¢Íƈ)Æth°dONLNd_¢ˆÆ&) , myBuff°dONLNdg¢&Æ2)0er°dONLNdi¢2Æ>) );°dONLNdz¢DÆ\){rea°dONLNd~¢\Æn)d d°dONLNdÅ¢nÆÄ)ata°dONLNdÑ¢ÄÆ»)  into buffer°dONLNdꢻƌ)H}°dONLNdì∞6º8(π6+IF (myErr = noErr) OR (myErr = eofErr) THEN°dONLNd¡æH f+BEGIN°dONLNd‘æD »)¸{move data into TERec}°dONLNdÓÃZÿz(’Z0TESetText(myBuffer, myLength, myData^^.editRec);°dONLNd"⁄ZÊ`*m°dONLNd#⁄`Ê¥)yErr := noErr;°dONLNd4ËHÙ`(ÒHEND;°dONLNd:ˆ6Æ(ˇ6DoReadFile := myErr;°dONLNdO*B(*END;ˇˇ¥º°dONLNdTl(+BThe ˇˇ44º°dONLNdXÄ(º)
  780. DoReadFileˇˇ¥º4º°dONLNdbº(¯)< function takeû4°dONLNdp¯()<s one p¨°dONLNdw(;)aramete¨°dONLNd~;(D)&r sºh°dONLNdÅD(∂)    pecifying the window to ra∏°dONLNdö∑(Ó)s ead data intÀ0°dONLNd¶Ó(ˆ)7o.À0°dONLNd®ˆ(˜) .°dONLNd©(l4Ø(1lThis function fi≤İdONLNdπ(Ø4¿)Crst riİdONLNdæ(¡4ó)/etrieves the handle to that window’s document r °dONLNdÌ(ò4™)◊ecorìİdONLNdÒ(™4Í)d and extracts .°dONLNd4l@Ö(=lthe fi°dONLNd4Ö@õ)le’s rR`°dONLNd 4õ@≠)efer$¿°dONLNd4≠@Ï)ence number fr˜ °dONLNd4Î@)>    om that r…İdONLNd'4@')*ecorõ‡°dONLNd+4'@K)d. Then õ‡°dONLNd34K@á)$
  781. DoReadFileõ‡°dONLNd=4á@≥)<  calls the õ‡°dONLNdH4≥@›),SetFPosõ‡°dONLNdO4›@fl)* .°dONLNdP@lL√(Ilfunction to set the fiy@°dONLNdf@ƒLT)X!le mark to the beginning of the fi˛ °dONLNdà@TLó)êle having that r ¿°dONLNdò@òL®)Defer∑‡°dONLNdú@®L·) ence number?¿°dONLNdß@·LÊ)9. .°dONLNd©LlXÇ(UlTherR`°dONLNd≠LÇXÙ)e is no need to check that R`°dONLNd»LÙX)rmyFileR`°dONLNdŒLXA)$
  782.  is nonzer$¿°dONLNdÿLAXo)) o, because $¿°dONLNd„LoXô).SetFPos$¿°dONLNdÍLôXü)* r˜ °dONLNdÏLûX’)eturns an err…İdONLNd˘L’XÍ)7or if .°dONLNdˇXldÄ(althe r¢`°dONLNdXÄdê)eferNİdONLNdXëdB)(ence number you pass in is not a valid fi#İdONLNd1XCdQ)≤le rİdONLNd5XQda)eferΔ†°dONLNd9Xadö) ence numberNİdONLNdDXödú)9..°dONLNdFjlv‹(slThe second parameter to °dONLNd^j‹v)pSetFPos°dONLNdejv&)* specifi°dONLNdmj&vJ) es the fi°dONLNdvjJvÙ)$(le positioning mode; in general, it can .°dONLNdûvlÇ    (l$contain one of the following values:.°dONLNd√élöä*CONST°dONLNdÕéêö¿)$fsAtMark°dONLNdŸéÿö)H= 0;°dONLNdflé¸öb)${at current mark}°dONLNdˆúꮓ(•ê fsFromStart°dONLNdúÿ®)H= 1;°dONLNd ú¸®Ï)$({set mark relative to beginning of file}°dONLNd9™ê∂Ã(≥ê
  783. fsFromLEOF°dONLNdG™ÿ∂)H= 2;°dONLNdM™¸∂¯)$*{set mark relative to logical end-of-file}°dONLNd}∏êƒÃ(¡ê
  784. fsFromMark°dONLNdã∏ÿƒ)H= 3;°dONLNdë∏¸ƒŒ)$#{set mark relative to current mark}°dONLNdµ–l‹´(ŸlIf you specify °dONLNdƒ–´‹€)?fsAtMark°dONLNdÖ€‹A)0, the mark is left wherR`°dONLNd„–A‹y)fever it’s curr$¿°dONLNdÒ–y‹Í)8ently positioned and the °dONLNd
  785. ‹lË(ÂlthirR`°dONLNd‹Ë≥)
  786. d parameteR`°dONLNd‹≥˃)4r of R`°dONLNd‹ƒËÓ)SetFPosR`°dONLNd$‹ÓËÙ)* iR`°dONLNd&‹ÙË)s ignor$¿°dONLNd-‹Ë_)ed. The other thr˜ °dONLNd>‹^ËÔ)M"ee constants let you position the .°dONLNd`ËlÙâ(Òlmark r¿°dONLNdfËäÙ2)(elative to either the beginning of the fifİdONLNdèË2Ùî)®le, the logical end-of-fiXİdONLNd®ËïÙ–)cle, or the curr°dONLNd∑Ë–Ù‡);ent °dONLNdªÙl (˝l%mark. If you specify one of these thrn‡°dONLNd‡Ù e)üee constants, the thir'‡°dONLNdˆÙfÏ)[d parameter contains the byte °dONLNdl t(    lof¿°dONLNdu 
  787. )    %fset (either positive or negative) frfl¿°dONLNd;
  788.  G)ïom the specifit¿°dONLNdIH Ç)>ed point. Her-‡°dONLNdVÉ ≤); e, the appr °dONLNda≤ ”)/opriate °dONLNdi l (lpositioning mode is rp¿°dONLNd~  V)^!elative to the beginning of the fi∫İdONLNd† V`)åle..°dONLNd§l*v('lIf °dONLNdßv*≤)
  789.  
  790. DoReadFile°dONLNd±≤*/)< successfully positions the fi°dONLNdœ/*È)}*le mark, it next determines the number of °dONLNd˘*l6™(3lbytes in the fi°dONLNd*™6ˆ)>le by calling the °dONLNd*ˆ6)LGetEOF°dONLNd *6û)$ function. The key step in the °dONLNd?*û6⁄)Ñ
  791. DoReadFile°dONLNdI*⁄6‹)< °dONLNdJ6lBÕ(?lfunction is the call to °dONLNdb6ÕBÒ)aFSRead°dONLNdh6ÒB)$    , which rR`°dONLNdq6Ba))eads the specifiR`°dONLNdÅ6aBΩ)Ged number of bytes fr$¿°dONLNdñ6ΩBÂ)\om the fi$¿°dONLNdü6ÂB)(le .°dONLNd¢BlN¨(Klinto the specifi= °dONLNd≤B≠N…)Aed bufWİdONLNd∏B…N’)fer™@°dONLNdªB‘NB) . In this case, the data is r0°dONLNdÿBCNi)o    ead into á°dONLNd·BiN∞)&a temporary buf°dONLNdB±NË)Hfer; then the .°dONLNd˛NlZ¬(Wldata is moved into °dONLNdN¬Z⁄)Vthe Tï°dONLNdNŸZ)    extEdit rg`°dONLNdNZ)(ecor9¿°dONLNd#NZ)d associated with the fi9¿°dONLNd;NZç)lle. 9¿°dONLNd?NçZ±)FSRead9¿°dONLNdEN±Z∑)$ r  °dONLNdGN∑ZÊ) eturns the °dONLNdRZlf‡(clnumber of bytes actually rR`°dONLNdlZ‡f˚)tead fr$¿°dONLNdrZ˚f#)om the fi$¿°dONLNd{Z#fK)(
  792. le in the $¿°dONLNdÖZKf{)(myLength$¿°dONLNdçZ{f≠)0
  793.  parameterg`°dONLNdóZ¨fØ)1.
  794. ã*ë¯4å*믠ålå¯
  795. ˇ·ˇ‚7^ˇˇ◊.ˇ◊°dONLNdôzlã{(álW(°dONLNdöz{ã‚)riting File Dataˇˇˇˇˇˇ®(á1
  796. °dONLNd´ëlù2(öl-Generally your application writes data to a fi´@°dONLNdŸë2ùK)Δle in r‹°dONLNd‡ëKùÓ)"esponse to the File menu commands °dONLNd    ùl©¶(¶lSave or Save i°dONLNd    ù¶©‡): As. However˘‡°dONLNd    ùfl©‘)98, your application might also incorporate a scheme that °dONLNd    R©lµ±(≤lIautomatically saves all open documents to disk every few minutes. It ther´ °dONLNd    õ©±µ¬(≤±efor °dONLNd    ü©√µÈ)e makes ˇ^@ˇ ˇˇˇˇ@
  797. ˇ·ˇ‚7^
  798. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä Using Files
  799. ~¿(‡1‡)-a¿)21(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿
  800. °dONLNd\äh‚(eäsense to isolate the rH °dONLNd\„h°)Y(outines that handle the menu commands fr≤`°dONLNd>\°hΔ)æom the rû@°dONLNdF\Δh¸)%outines that °dONLNdShät(qäXhandle the actual writing of data to disk. This section shows how to write the data stor˝‡°dONLNd´ht(qed °dONLNdÆtäÄ¢(}äin a ToİdONLNd¥t¢Ä»)    extEdit rK`°dONLNdΩt»Ä⁄)&ecorø¿°dONLNd¡t⁄Ä˚)d to a fi  °dONLNd t¸Ä)"le. See % °dONLNd“tÄ\)“Saving a File”}İdONLNd·t\ÄÅ)B
  801.  for instrQ@°dONLNdÎtÇÄ)&uctions on handling the Save °dONLNdÄäå¥(âä    and Save æ`°dONLNdÄ¥å)*As menu commands.°dONLNd#íäû (õä It is very easy to write data fr∫İdONLNdCí û?)Å om a specifir °dONLNdOí@û\)5ed bufåİdONLNdUí\û¢)fer into a specifi¸`°dONLNdgí¢ûµ)Fed finİdONLNdlí∂û¬)le. Ú‡°dONLNdpí¬û») Y≥`°dONLNdqí»ûˆ)
  802. ou simply .°dONLNd{ûä™ (ßäposition the fi°dONLNdäû ™^)@!le mark at the beginning of the fi°dONLNd¨û^™Ü)î
  803. le (using ,
  804. Courier°dONLNd∂ûÜ™∞)(SetFPos°dONLNdΩû∞™)*), write the data into °dONLNd‘™ä∂£(≥äthe fi°dONLNd⁄™£∂À)
  805. le (using °dONLNd‰™À∂ı)(FSWrite°dONLNdΙı∂)*), and rR`°dONLNdÛ™∂G)  esize the fiR`°dONLNdˇ™G∂)2+le to the number of bytes actually written °dONLNd*∂ä¬ß(øä(using °dONLNd1∂߬À)SetEOF°dONLNd7∂À¬‘)$). °dONLNd:∂‘¬)     Listing 1-8°dONLNdE∂¬v)0 illustrates this sequence.
  806. ‰HË4ÂHÁ"ÂHa
  807. ˇ·ˇ‚7^    .°dONLNdˇˇ(‚ä Listing 1-8°dONLNda⁄ŒÂ÷)DW’ê°dONLNdb⁄÷Â)riting data into a fiŸê°dONLNdw⁄Â$)Gle
  808. .°dONLNdzÒH˝(˙HFUNCTION DoWriteData (myWind°dONLNdñÒ˝¸)®ow°dONLNdòÒ¸˝P) : WindowPtr; m°dONLNd¶ÒP˝t)TyTemp:°dONLNd¨Òt˝⁄)$ Integer): OSErr;°dONLNdøˇH Z(HVAR°dONLNdƒT~+ myData:°dONLNdœú‰)H MyDocRecHnd;°dONLNd„,⁄)ê{handle to a document record}°dONLNdT'x($TmyLeng°dONLNd    x'ä)$th:°dONLNdú'Ã)$LongInt;°dONLNd ,'¯)ê"{number of bytes to write to file}°dONLNdD)T5~(2TmyText:°dONLNdO)ú5“)H    TEHandle;°dONLNd`),5Œ)ê{handle to TextEdit record}°dONLNd}7TCx(@TmyBuff°dONLNdÉ7xCÑ)$er°dONLNdÖ7ÑCä) :°dONLNdä7úCΔ)Handle;°dONLNdô7,CÏ)ê {handle to actual text in TERec}°dONLNdªETQx(NTmyVol:°dONLNd≈EúQÃ)HInteger;°dONLNd’E,Q˛)ê#{volume reference number of myFile}°dONLNd˚ST_x(\TmyErr:°dONLNdSú_¿)HOSErr;°dONLNd aHmf(jHBEGIN°dONLNdoT{>+ 'myData := MyDocRecHnd(GetWRefCon(myWind°dONLNd:o>{J)Íow°dONLNd<oJ{\) ));°dONLNdNob{˛){get window’s data record}°dONLNdl}Tâˆ(ÜTmyText := myData^^.editRec;°dONLNdñ}bâ§(Üb {get TERec}°dONLNd£ãTóx(îTmyBuff°dONLNd©ãxóÑ)$er°dONLNd´ãÑóˆ)  := myText^^.hText;°dONLNdÕãbó»)fi{get text buffer}°dONLNd‡ôT•x(¢TmyLeng°dONLNdÊôx•Ñ)$th°dONLNdËôÑ•)  := myText^^.teLength;°dONLNdôb•Ê)fi{get text buffer size}°dONLNd&µT¡¥(æTmyErr := SetFPos°dONLNd6µ¥¡‰)`(myTemp,°dONLNd>µ‰¡J)0 fsFromStart, 0);°dONLNd^µb¡Ú)~{set file mark at start}°dONLNdx√Tœ“(ÃTIF myErr = noErr THEN°dONLNdú√bœÚ(Ãb{write buffer into file}°dONLNd∑—f›Δ(⁄fmyErr := FSWrite°dONLNd«—Δ›ˆ)`(myTemp,°dONLNdœ—ˆ› )0 myLeng°dONLNd÷— ›,)*th°dONLNdÿ—,›\) , myBuff°dONLNd‡—\›n)0er^°dONLNd„—n›z));°dONLNdËflTΓ(ËTIF myErr = noErr THEN°dONLNd flbÎŒ(Ëb{adjust file size}°dONLNd!Ìf˘¿(ˆfmyErr := SetEOF°dONLNd0Ì¿˘)Z(myTemp,°dONLNd8Ì˘)0 myLeng°dONLNd?Ì˘&)*th°dONLNdAÌ&˘2) );°dONLNdF˚T“(TIF myErr = noErr THEN°dONLNdj˚bÚ(b{find volume file is on}°dONLNdÖ    fÿ(fmyErr := GetVRefNum°dONLNdò    ÿ)r(myTemp,°dONLNd†    8)0 myVol);°dONLNd´T#“( TIF myErr = noErr THEN°dONLNdœb#∂( b{flush volume}°dONLNdfi%H1N(.H °dONLNd·%f1)myErr := FlushVol(NIL, myVol);°dONLNd3T?“(<TIF myErr = noErr THEN°dONLNd&3b?¯(<b{show file is up to date}°dONLNdMAfM(JfmyData^^.windowDirty := FALSE;°dONLNdnOT[“(XTDoWriteData := myErr;°dONLNdÑ]Hi`(fHEND;°dONLNdâuäÅû+BThe °dONLNdçuûŇ) DoWriteData°dONLNdòu‡Å)B  function fi°dONLNd§uÅ!)/rst rR`°dONLNd©u!Å`)etrieves the Tg`°dONLNd∑u_Åá)>    extEdit r9¿°dONLNd¿uáÅô)(ecor  °dONLNdƒuôÅ)d attached to the specifi  °dONLNd›uÅ)oed .°dONLNd‡Åäç(ääwindow and extracts the addrV‡°dONLNd¸Åç´)Ö%ess and length of the actual text buf¢¿°dONLNd!Å´ç¿)úfer frK¿°dONLNd'Å¡çÈ)    om that r∞`°dONLNd0ÅÈç˚)(ecor$¿°dONLNd4Ÿç)d. ˇˇÏ˙.°dONLNd7çäôƒ(ñäThen it calls ˇˇΔÓFÓ°dONLNdEç≈ôÔ);SetFPosˇˇÏ˙FÓ°dONLNdLçÔôÛ)*, ˇˇΔÓ3˰dONLNdNçÙô)FSWriteˇˇÏ˙3˰dONLNdUçô5)*, and ˇˇΔÓ‹°dONLNd[ç6ôZ)SetEOFˇˇÏ˙‹°dONLNdaçZôŒ)$ as just explained. Finally¶°dONLNd|çÕô—)s, ˇˇΔÓí˛°dONLNd~ç“ô) DoWriteDataˇˇÏ˙í˛°dONLNdâçô)B °dONLNdäôä•=(¢ä&determines the volume containing the fi°dONLNd±ô=•w)≥le (using the °dONLNdøôw•≥):
  809. GetVRefNum°dONLNd…ô≥•˘)< function) and fl°dONLNd⁄ô˘•)Fushes °dONLNd‡•ä±·(Æäthat volume (using °dONLNdÛ•·±)WFlushVol°dONLNd˚•±`)0). This is necessar°dONLNd    •`±ä)O
  810. y to ensurR`°dONLNd    •ä±√)*e that both tR`°dONLNd    %•√±ÿ)9he fiR`°dONLNd    *•ÿ±‹)lR`°dONLNd    +•‹±)e’s dR`°dONLNd    0•±˙)atR`°dONLNd    2•˙±)
  811. a and .°dONLNd    8±äΩç(∫ät¬`°dONLNd    9±çΩ†)he fiÍ °dONLNd    >±†ΩÂ)le’s catalog entr°dONLNd    O±ÊΩ˜)Fy ar‰ °dONLNd    S±ˆΩ%)
  812. e updated.ˇ@ˇ ˇˇˇˇ@
  813. ˇ·ˇ‚7^
  814. 4*\˜, Palatino.+l"CHAPTER €`)\1,     Helvetica    (@lIntroduction to File Management4⁄*˙¯
  815. (‡*1 )-c)22    )9 Using Files*Draft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯l Second line.4^*¿¯
  816. ˇˇO».°dONLNd\lh≥(elNotice that the ,
  817. Courierˇ˝ÔXoX°dONLNd\¥hˆ)H DoWriteDataˇˇO»oX°dONLNd\ˆhå)B" function takes a second parameter@‡°dONLNd=\åhê)ñ, ˇ˝ÔXê®°dONLNd?\êh¥)myTempˇˇO»ê®°dONLNdE\¥h˜)$, which should .°dONLNdThltÜ(qlbe a fifi°dONLNd[hÜtî)le r’°dONLNd_hît§)eferÅ °dONLNdch•t*)ence number of a temporary fihİdONLNdÄh+tK)Ü    le, not tf °dONLNdâhLt_)!he fi燰dONLNdéh_tm)le rч°dONLNdíhmt})efer1°dONLNdñh~t€)ence number of the fi©¿°dONLNd´h€tÂ)]le °dONLNdÆtlÄ™(}lassociated witÒ†°dONLNdºt™ÄÀ)>h the w˜`°dONLNd√tÀÄfl)!indoB`°dONLNd«t‡Äq)w whose data you want to write.à`°dONLNdÊtqİ)ë  If you wer¨ °dONLNdÒt°Ä´)0e t8 °dONLNdÙt¨Ä⁄) o pass the °dONLNdˇÄlåo(âlrE°dONLNdÄpåÄ)eferÒ °dONLNdÄÄå›)ence number of the fii‡°dONLNdÄfiåd)^le associated with the window @°dONLNd6Äcåe)Ö,J@°dONLNd7Äfå¿) you would risk corrㇰdONLNdKÄ¿å)Z upting the .°dONLNdVålòs(ïlfi°dONLNdXåsòˇ)le. For when you position the fi°dONLNdxåˇòì)å!le mark at the beginning of the fi°dONLNdöåìò≈)î le and call °dONLNd¶å≈òÔ)2FSWrite°dONLNd≠åÔòÙ)*, ˇˇõr°dONLNdØòl§™(°lthe existing fi∂‰°dONLNdæò™§)>le data is overwritten. If ˇ˛“V¿°dONLNdŸò§D)pFSWriteˇˇõr¿°dONLNd‡òD§ )* does not complete successfully&°dONLNdˇò §¯)Ü, it is very .°dONLNd §l∞±(≠llikely that the fi·@°dONLNd§±∞K)E$le on disk does not contain the corryİdONLNdB§L∞†)õect document data.°dONLNdU∂l¬r(ølTµ¿°dONLNdV∂q¬¶) o avoid corr °dONLNdb∂߬›)6 upting the fiÄ¿°dONLNdo∂›¬‡)6;le containing the saved version of a document, always call .°dONLNd™¬lŒÆ(Àl DoWriteData°dONLNdµ¬ÆŒ˜)B specifying the fPİdONLNdΔ¬˜Œ
  818. )Iile r"‡°dONLNdÀ¬
  819. Œ)eferı@°dONLNdœ¬Œá)ence number of some new
  820. @°dONLNdʬጬ)l, temporary f⁄¿°dONLNdÛ¬¡ŒÔ): ile. Then, °dONLNd˛Œl⁄á(◊lwhen °dONLNdŒá⁄…) DoWriteData°dONLNdŒ…⁄/)B completes successfullyd@°dONLNd%Œ.⁄≈)e#, you can swap the contents of the °dONLNdH⁄lÊ•(„l temporary fi°dONLNdT⁄•Ê)9le and the existing fi°dONLNdj⁄Ê8)]le using the °dONLNdw⁄8Êò)6FSpExchangeFiles°dONLNdá⁄òÊ√)`  function. °dONLNdí⁄√ÊÛ)+ Listing 1-8°dONLNdù⁄ÛÊı)0 .°dONLNdûÊlÚÍ(Ôlillustrates how to update a fi¿°dONLNdºÊÎÚ…)4le on disk safely; it shows a sequence of updating, °dONLNdÚl˛o(˚lrE°dONLNdÒÚp˛˛)enaming, saving, and deleting fiEİdONLNdÚ˛˛*)é les that prQ¿°dONLNdÚ*˛À),&eserves the contents of the existing fi     °dONLNdCÚÃ˛Ì)¢    le until °dONLNdL˛l
  821. fl(lthe new version is safely rZİdONLNdg˛fl
  822. Ò)secorŒ‡°dONLNdk˛Ò
  823. )ded. 
  824. ,*0¯4-*/¯"-*a
  825. ˇ·ˇ‚7^    °dONLNdˇˇ(*l Listing 1-9°dONLNdq"∞-‚)D Updating a fi‡°dONLNd~"„-)3    le safely
  826. .°dONLNdà9*EÃ(B*FUNCTION DoWriteFile (myWin°dONLNd£9ÃE‰)¢dow)°dONLNdß9‰E): OSErr;°dONLNd±G*S<(P*VAR°dONLNd∂U6a`+ myData:°dONLNd¡U~aΔ)H MyDocRecHnd;°dONLNd“Uÿa∞)Z${handle to window’s document record}°dONLNd˘c6o<(l6m°dONLNd˙c<oN)yFS°dONLNd˝cNof)pec:°dONLNdc~o®)0FSSpec;°dONLNdcÿoz)Z{FSSpec for file to update}°dONLNd.q6}<(z6m°dONLNd/q<}f)yTSpec:°dONLNd:q~}®)BFSSpec;°dONLNdFqÿ}z)Z{FSSpec for temporary file}°dONLNdc6ã`(à6myTime:°dONLNdn~ãÆ)HLongInt;°dONLNd{ÿãº)Z&{current time; for temporary filename}°dONLNd£ç6ô`(ñ6myName:°dONLNdÆç~ô®)HStr255;°dONLNd∫çÿôh)Z{name of temporary file}°dONLNd‘õ6ß<(§6m°dONLNd’õ<ß`)yTemp:°dONLNdflõ~߯)BInteger;°dONLNdÏõÿߌ)Z){file reference number of temporary file}°dONLNd©6µ`(≤6myVRef:°dONLNd"©~µÆ)HInteger;°dONLNd/©ÿµ⁄)Z+{volume reference number of temporary file}°dONLNd\∑6√f(¿6myDirID:°dONLNdh∑~√Æ)HLongInt;°dONLNdu∑ÿ√ò)Z {directory ID of temporary file}°dONLNdó≈6—Z(Œ6myErr:°dONLNd°≈~—¢)HOSErr;°dONLNd®”*flH(‹*BEGIN°dONLNdØ·6Ì + 'myData := MyDocRecHnd(GetWRefCon(myWind°dONLNd÷· Ì,)Íow°dONLNdÿ·,Ì8) ))°dONLNd⁄·8ÌD) ;{°dONLNd‹·DÌŒ) get that window’s data}°dONLNd˜Ô6˚B(¯6my°dONLNd˘ÔB˚H) F°dONLNd˙ÔH˚)Spec := myData^^.fileFSSpec;°dONLNd$Ô2˚Ê)Í{get FSSpec for existing file}°dONLNdE 6Æ(6GetDateTime(myTime);°dONLNdg 2‡)¸{create a temporary filename}°dONLNdÜ6%fi("6NumToString(myTime, myName);°dONLNd¶56AŒ*D{find the temporary folder on file’s volume; create it if necessary}°dONLNdÏC6O∫*myErr := FindFolder(my°dONLNdC∫O¿)ÑF°dONLNdC¿Oå)"Spec.vRefNum, kTemporaryFolderType°dONLNd%CåOí)Ã,°dONLNd/Q¥]∫(Z¥k°dONLNd0Q∫]) CreateFolder°dONLNd<Q])H, m°dONLNd?Q]t)yVRef, myDirID);°dONLNdQ_6k¥(h6IF myErr = noErr THEN°dONLNdt_2kÊ)¸{make an FSSpec for temp file}°dONLNdïmHyV(vH-myErr := FSMakeFSSpec(myVRef, myDirID, myName°dONLNd¬mVyí(vV
  827. , myTSpec)°dONLNdÃmíyò)<;°dONLNd÷{6á¥(Ñ6IF myErr = noErr THEN°dONLNd˘{2á»)¸{create a temporary file}°dONLNd    âHï¥(íHmyErr := FSpCreate°dONLNd    'â¥ïÍ)l    (myTSpec,°dONLNd    0âÍï∞)6! 'trsh', 'trsh', smSystemScript);°dONLNd    Tó6£¥(†6IF myErr = noErr THEN°dONLNd    wó2£‡)¸{open the newly created file}°dONLNd    ó•H±¥(ÆHmyErr := FSpOpenDF°dONLNd    ©•¥±Í)l    (myTSpec,°dONLNd    ≤•ͱ,)6  fsRdWrPerm°dONLNd    Ω•,±b)B    , myTemp)°dONLNd    Δ•b±h)6;°dONLNd    ”≥6ø¥(º6IF myErr = noErr THEN°dONLNd    ˆ≥2ø‡)¸{write data to the temp file}ˇ@ˇ ˇˇˇˇ@
  828. ˇ·ˇ‚7^
  829. 4H\, Palatino.+ä"CHAPTER €`)\1,     Helvetica    (@äIntroduction to File Management4⁄ä˙(‡ä Using Files
  830. ~¿(‡1‡)-a¿)23(ÔäDraft. PreliminaryVP):, Confi)dential. ©1991 ˘Å)0Apple ComputerÒ)7, Inc. Ìë)1o¡)1/7/91(¯ä Second line.4^H¿,
  831. Courier
  832. .°dONLNd\fh(efmyErr := DoWriteData(myWind°dONLNd\hJ)¢ ow, myTemp)°dONLNd&\JhP)B;°dONLNd*jTv“(sTIF myErr = noErr THEN°dONLNdMjPvÏ)¸{close the temporary file}°dONLNdjxfÑΔ(ÅfmyErr := FSClose°dONLNdzxΔш)`(myTemp)°dONLNdÇxˆÑ¸)0;°dONLNdÜÜTí“(èTIF myErr = noErr THEN°dONLNd©ÜPí¯)¸{swap data in the two files}°dONLNd»îf†¸(ùfmyErr := FSpExchangeFiles°dONLNd·î¸†2)ñ    (myTSpec,°dONLNdÍî2†D)6 my°dONLNdÌîD†J)F°dONLNdÓîJ†n)Spec);°dONLNd˛¢TÆ“(´TIF myErr = noErr THEN°dONLNd!¢PÆÚ)¸{delete the temporary file}°dONLNd?∞fº“(πfmyErr := FSpDelete°dONLNdQ∞“º)l
  833. (myTSpec);°dONLNd]æT “(«TIF myErr = noErr THEN°dONLNduÃfÿ+myData^^.windowDirty := FALSE;°dONLNd†ÃPÿÊ)Í{mark window’s not dirty}°dONLNdª⁄TÊ“(„TDoWriteFile := myErr;°dONLNd—ËHÙ`(ÒHEND;.°dONLNd÷ä M+B-The essential idea behind this “safe save” pr{°dONLNdM )√+ocess is to save the data in memory into a °dONLNd. ä•(änew fi˛¿°dONLNd4 •~)le and then to exchange the contents of the new fi˘@°dONLNdf )⁄le and the old version of the fiÒ†°dONLNdÜ )Ñle .°dONLNdâä$π(!ä by calling °dONLNdîπ$)/FSpExchangeFiles°dONLNd§$)`. °dONLNd¶$~)FSpExchangeFiles°dONLNd∂~$)` does not move the data on the .°dONLNd’$ä0 (-ävolume; it mer6@°dONLNd„$À0Ê)AAely changes the information in the volume’s catalog and, if the fi∞@°dONLNd%$Ê0˝(-Êles ar‰@°dONLNd+$˝0)e °dONLNd-0ä<Õ(9äopen, in their fiİdONLNd>0Œ<Ô)Dle contr°dONLNdF0Ô<ß)!+ol blocks (FCBs). The catalog entry for a fi+†°dONLNdr0ß<÷)∏ le contains,Zapf Dingbats°dONLNd~EäLè(Kän
  834. °dONLNdÄBñNú) fiå¿°dONLNdÇBúNt)3elds that describe the physical data, such as the fiuİdONLNd∂BuN
  835. )Ÿ$rst allocation block, physical end, °dONLNd⁄NñZ(Wñand logical end of both the rŒÄ°dONLNd˜NZ*)|esour¿°dONLNd¸N+Zv)ce and data forks°dONLNdcäjè(iän
  836. °dONLNd`ñlú) fiå¿°dONLNd`úlÆ)eldsóİdONLNdcÆjØ) 
  837. â`°dONLNd`∞l)that describe the fiİdONLNd+`lB)Rle within the fi1İdONLNd;`Blò)@le system, such as fi °dONLNdP`ôl”)Wle ID and par °dONLNd]`”l):ent dirD†°dONLNdd`l)ectory °dONLNdklñx°(uñID°dONLNdn~ää (áäFields that describe the data ró¿°dONLNdç~ äo)Çemain with the data; fi
  838. İdONLNd§~pä÷)delds that describe the fi`°dONLNdΩ~÷ä‰)fle r `°dONLNd¡~‰ä)emain °dONLNd«ääñ∑(ìä
  839. with the fiΩ@°dONLNd“ä∑ñfl)-
  840. le. The cr‡@°dONLNd‹äflñ)(eation date r@°dONLNdÈäñf)8emains with the fiY‡°dONLNd˚äfñ†)Ole; the modifi√†°dONLNd    ä†ñ÷):cation date rí@°dONLNdä◊ñ)7 emains with .°dONLNd"ñ䢵(üä    the data.°dONLNd,ñµ¢Â)+  (For a morR`°dONLNd7ñ¢i)0e complete description of the R`°dONLNdUñi¢…)ÑFSpExchangeFilesR`°dONLNdeñ…¢˝)` function, seR`°dONLNdrñ˝¢)4e tR`°dONLNduñ¢) he .°dONLNdx¢äÆM(´ä+chapter “The File Manager” in this volume.)
  841. ”HŸ4‘HŸ ‘ä‘
  842. ˇ·ˇ‚7^ˇˇ◊ˇ